[英]Why do generator expressions have lower recursion depth when compared to map objects in python 3, despite considered more pythonic?
例如,我们可以在生成器中使用递归定义斐波那契数列:
from itertools import pairwise
def fibs():
yield 0
yield 1
yield from map(sum, pairwise(fibs()))
for index, result in enumerate(fibs()):
print(index, result)
如果我们尝试运行它,它会在索引为 1025 时放弃,并在递归深度超出错误的情况下崩溃。 下面我复制了 output 的结尾:
1024 4506699633677819813104383235728886049367860596218604830803023149600030645708721396248792609141030396244873266580345011219530209367425581019871067646094200262285202346655868899711089246778413354004103631553925405243
1025 7291993184377412737043195648396979558721167948342308637716205818587400148912186579874409368754354848994831816250311893410648104792440789475340471377366852420526027975140687031196633477605718294523235826853392138525
Traceback (most recent call last):
File "/home/user/Área de Trabalho/fibs1.py", line 6, in fibs
yield from map(sum, pairwise(fibs()))
File "/home/user/Área de Trabalho/fibs1.py", line 6, in fibs
yield from map(sum, pairwise(fibs()))
File "/home/user/Área de Trabalho/fibs1.py", line 6, in fibs
yield from map(sum, pairwise(fibs()))
[Previous line repeated 997 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
现在我们可以尝试通过用生成器表达式替换 map 来更改它,使其更像 pythonic:
from itertools import pairwise
def fibs():
yield 0
yield 1
yield from (sum(pair) for pair in pairwise(fibs()))
for index, result in enumerate(fibs()):
print(index, result)
现在的问题是,这个版本的运行时间只有第一个版本的一半,在只有 513 的深度内爆并出现更大的错误消息,同时它还返回最大递归深度超出错误:
512 44893845313309942978077298160660626646181883623886239791269694466661322268805744081870933775586567858979269
513 72639767602615659833415769076743441675530755653534070653184546540063470576806357692953027861477736726533858
Traceback (most recent call last):
File "/home/user/Área de Trabalho/fibs2.py", line 6, in <genexpr>
yield from (sum(pair) for pair in pairwise(fibs()))
File "/home/user/Área de Trabalho/fibs2.py", line 6, in fibs
(... this repeats a lot, exceeds maximum character limit in SO)
yield from (sum(pair) for pair in pairwise(fibs()))
File "/home/user/Área de Trabalho/fibs2.py", line 6, in fibs
yield from (sum(pair) for pair in pairwise(fibs()))
RecursionError: maximum recursion depth exceeded while calling a Python object
所以我问,为什么不同?
我在玩 Joel Grus 在他的博客中发布的类似 haskell 的斐波那契实现时注意到了这个问题,但在 python 3.10 发布时将其更改为使用 itertools 模块中引入的 pairwise。 这样就需要一次导入(成对),而不是三个导入(add、islice、tee)和一个助手 function 定义(tail)。
您所指的“耐力”与延迟评估和具有配置的最大堆栈深度的尾递归有关。
Common Lisp 和 Scheme 之间最大的区别是后者绝对需要适当的尾递归支持。 Lisp 代码可能能够永远循环,但它保证适合该格式的方案代码不会增加堆栈。
在 python itertools
上下文中,您实际上是在抱怨那不是规范的一部分。 而且,以一种或另一种方式表达想法可能会在每次迭代中推动一个或一对堆栈框架。 好,可以。 您正在测试的工具不是为符合该要求而编写的,当您推动该方面时,它们可能会出现不足。 在设计一个解决方案时,您可能会考虑使用一个小的lru_cache来修补,但我知道这只是一个学术练习,试图探索极限,而您已经找到了它们。
代码正在按照您的要求进行操作。 是的,还有设计更好代码的空间。 Go吧!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.