|
发表于 2023-4-2 00:16:53
|
显示全部楼层
本楼为最佳答案

即使你删除第10行的 return li,这个函数仍然不能被认为是尾递归的。
这是因为在递归调用 glob(i, name, li) 之后,函数没有直接返回该递归调用的结果。
实际上,在递归调用之后,仍然会继续执行for循环(当 i.is_dir() 不为 True 的情况下)。
为了让你更好地理解,我将解释一下尾递归的概念。尾递归是指一个函数的递归调用发生在它的最后一步,
并且在递归调用之后没有任何其他操作。这使得编译器或解释器可以对递归过程进行优化,避免堆栈溢出。
在尾递归中,递归调用的返回值不需要与任何其他值相结合,也不需要进行任何操作。
在你的示例中,glob 函数的递归调用并不是在最后一步进行的,而且递归调用之后仍然需要执行循环。因此,这个函数不是尾递归的。
如果你希望将此函数转换为尾递归形式,可以尝试将其重构为一个内部函数,该内部函数接受一个额外的参数,如下所示:
- from pathlib import Path
- def glob(pa: Path, name: str):
- def _glob(pa: Path, name: str, li: list):
- for i in pa.iterdir():
- if i.is_file() and i.suffix == name:
- li.append(i.name)
- elif i.is_dir():
- li = _glob(i, name, li)
- return li
- return _glob(pa, name, [])
- print(glob(Path.cwd(), ".txt"))
复制代码
在这个修改后的版本中,我们将逻辑放在了一个名为 _glob 的内部函数中。
这个内部函数接受一个名为 li 的额外参数,这样我们就可以在每次递归调用中将其传递给下一层。
这使得递归调用成为函数的最后一步操作,从而满足尾递归的条件。
尽管这个版本看起来更接近尾递归,但需要注意的是,Python 并不会自动优化尾递归。
因此,这种改进在 Python 中并没有实质性的性能提升。在实际应用中,使用迭代方法通常是更好的选择,因为它不会导致堆栈溢出,并且性能更加可靠。
迭代的例子:
- from pathlib import Path
- from collections import deque
- def glob(pa: Path, name: str):
- li = []
- q = deque([pa])
- while q:
- current_dir = q.popleft()
- for i in current_dir.iterdir():
- if i.is_file() and i.suffix == name:
- li.append(i.name)
- elif i.is_dir():
- q.append(i)
- return li
- print(glob(Path.cwd(), ".txt"))
复制代码 |
|