| 
 | 
 
 
发表于 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"))
 
 
  复制代码 |   
 
 
 
 |