def f1():
f1()
我们都知道在Python中调用这个函数会产生RuntimeError: maximum recursion depth exceeded
我写了一个简洁的修改版本:
def f2():
try:
f2() #This line throws an error
finally: #except works too
f2() #This line does not throw an error!
第二个函数永远运行而不会抛出RuntimeError
。更重要的是,我无法通过 Ctrl C 组合来阻止它。
我不明白为什么调用f2()不会抛出RuntimeError
。你能解释一下吗?
答案 0 :(得分:4)
异常仍然被抛出,但是在Python之前可以显示它你再次调用f2()
。
所以每次提出异常时,你都会潜入另一个电话。允许那个递归调用(因为我们比限制低一步),我们越过限制,再次引发异常,finally
处理程序在另一个调用中偷偷摸摸,几乎是无限的。
CTRL-C
并未结束该计划;引发异常(KeyboardInterrupt
),但finally:
处理程序再次将您送回递归。
你现在正以这样的速度下降,你进入了解释器的轨道。
所有都结束,但finally
处理程序在堆栈完全展开之前添加指数增长的额外调用数量:
>>> import sys
>>> def f2(depth=0, final=0):
... try:
... print depth
... f2(depth + 1, final)
... finally:
... print 'finally:', final
... f2(depth, final + 1)
...
>>> sys.setrecursionlimit(5)
>>> f2()
0
1
2
3
finally: 0
finally: 0
2
finally: 1
finally: 0
1
2
finally: 1
finally: 1
1
finally: 2
finally: 0
0
1
2
finally: 1
finally: 1
1
finally: 2
finally: 1
0
1
finally: 2
finally: 2
0
finally: 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in f2
File "<stdin>", line 7, in f2
File "<stdin>", line 7, in f2
File "<stdin>", line 7, in f2
RuntimeError: maximum recursion depth exceeded
答案 1 :(得分:4)
当堆栈填满时,它会在f2
内调用try
,直到达到最大递归深度。
一旦达到,就会引发RuntimeError
,由finally
反过来提升相同的RuntimeError
,但现在提升到早期的堆栈,它会传递给finally
。
在那里,它再次超过最大深度。
当提出KeyboardInterrupt
时,程序会一直移动到finally
,并且不会退出。
它不会在技术上永远运行,因为只有finally
。也就是说,(感谢评论),它允许指数级更多的调用,这非常接近无穷大。递归深度为100将变为2 100 == 1267650600228229401496703205376。
如果每次通话花费1毫秒,则需要 4650亿年才能完成。这只是100的深度