前言
一切要从小伙子在python学习网站上的一道练习题说起。题目如下:
简单说,就是打印一个文件夹下,所有文件名字,包括所有子文件夹中的文件。如果只是用 python 提供的内置模块,是非常容易。但是这题却限制了,不允许使用内置模块。
小伙子心想,这明显是进阶题目呀。虽然网站提供了提示功能,但小伙子还是打算自己尝试一下。
正常思路:
显然不行呀,每多一层子文件夹,就要写多一次 for 循环。但我无法确定到底有多少层子文件夹。
无奈之下,只能使用”提示”功能,得到的提示是”递归”。
递归
经过一番资料查阅,小伙子终于知道问题出在哪。
小伙在自己电脑上验证一番,发现确实可以达到要求。自信满满上传到网站上,却提示:”调用栈溢出!”
这就是递归的缺点,太内卷(内耗严重)了。显然,这题目的目的不仅仅是学习递归思维,而是充分了解其优缺点。
递归的过程
要了解优缺点,必须深入了解递归的流程。
假设目前文件夹的子文件夹深度有3层,那么调用流程如下图:
但是要注意,当执行到上图第三层的时候,前面的第一,二层的函数只是执行到一半而已,一个函数没有执行完毕,后续第三层函数执行结束后,要跳回去第二层继续执行。但是 python 怎么保存前面层的调用信息(每一层的变量数据,执行到哪一行等信息)?
这里的第三层只要没有文件夹,那么它自然不会再次调用函数,最后就会结束。这是递归的退出条件,必须保证递归存在退出条件,否则就是死循环
在 python 中,函数的调用信息保存在一个叫帧的东西里面,我以前就有相关文章讲解,相关链接放在文末
这就是调用栈发挥作用的时候。看下图:
这里我们需要关注的重点就是左边的容器
那么,为什么说递归太”内卷”了?因为如果文件夹层级很深,那么调用栈就会堆积大量的调用信息,而调用栈的容量有限,很容易出现栈溢出。
小伙子了解到这些知识后,感觉到自己无法解决,只能查看提示——“模拟栈。用 list 保存,可存放容量比调用栈容量大得多”
用 list 模拟栈
回到一开始的思路:
修改为无限循环
小伙子非常满意,感觉自己的 python 水平大幅提升。但是题目竟然还没有结束。
题目提示:”恭喜你,解决了问题。不过,现在函数不能应对需求变化,只能打印路径。请把函数中对路径的处理代码移除,又能保证调用者可以灵活使用”
小伙子随便想一下,就可以想到3种实现方式:
生成器
把一个函数变得通用,本质上就是把处理逻辑交给调用者。python 中使用 yield 返回生成器结果是最方便的。
调用者就像处理集合的方式,就可以执行自己的逻辑。
不要忘记一键三连。你的点赞、收藏、关注,是我创作的动力。
推荐文章:
Python进阶:你定义的变量到底保存在哪里Python进阶系列:Python遍历的秘密
-
扫码下载安卓APP
-
微信扫一扫关注我们
微信扫一扫打开小程序
手Q扫一扫打开小程序
-
返回顶部
发表评论