- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
考虑这个递归函数,由我的一位同事开发:
def a():
try:
a()
except:
a()
如果您运行它,(Python 2.7) 解释器会挂起。这让我感到惊讶,因为我预计一旦达到递归深度(比如 N),它就会抛出一个 RuntimeError
,跳转到第 (N-1) 个 except
block ,得到另一个RuntimeError
,跳转到第(N-2)个except
等
所以我稍微充实了这个函数以进行调试:
y = 10000
def a(x=0):
global y
if y:
y -= 1
try:
print "T: %d" % x
a(x+1)
except RuntimeError:
print "E: %d" % x
a(x+1)
y
只是为了强制函数在某个时刻终止,我认为它不会改变函数的行为。在我的解释器中(递归限制为 1000)调用 a()
会产生如下序列:
T: 998
E: 998
E: 997
T: 998
E: 998
E: 990
T: 991
T: 992
T: 993
T: 994
T: 995
T: 996
T: 997
T: 998
E: 998
E: 997
T: 998
E: 998
E: 996
看着更长的序列,我无法从中辨别出任何真实的模式(尽管我承认我没有尝试绘制它)。我想也许堆栈在 N 和 N-M 调用之间来回跳动,其中每次递归深度达到时 M 都会递增。但是 y
有多大似乎并不重要,堆栈展开的调用不会超过大约八次。
那么 Python 内部到底发生了什么?这种行为有规律吗?
最佳答案
这是一个有趣的问题。您的预期行为不是现实的原因似乎是当 RuntimeError 被引发时,有问题的“太递归”堆栈框架被关闭。这意味着当异常在下一个较低的堆栈帧中被捕获时,该帧可以再次向上递归,直到它达到限制。
也就是说,您预计一旦达到递归深度(比如 N),它就会:
实际情况是:
此外,每个“再次递归一直到 N”必须使用异常-递归-异常的相同增量过程展开。因此,递归比您预期的要多得多。
很难在输出中看到的原因是您的原始代码没有区分具有相同 x
值的多个调用。当进行第 1001 次调用时,第 1000 次调用中的异常将控制权返回给第 999 次调用。此调用然后使用 x=1000
进行另一个调用,创建具有特定 x
值的调用的并行“沿袭”。
可以通过如下修改原始代码来查看行为:
y = 2000
def a(x=0, t=''):
print(t + "In a({0})".format(x))
global y
if y:
y -= 1
try:
a(x+1, t)
except RuntimeError:
print(t + "*** E: %d" % x)
a(x+1, t+'\t')
这会添加缩进,这样您就可以看到哪些调用来自哪些其他调用。结果输出的示例是:
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 985
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 984
In a(985)
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 985
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 983
In a(984)
In a(985)
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 985
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 984
In a(985)
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
*** E: 985
In a(986)
In a(987)
*** E: 987
*** E: 986
In a(987)
*** E: 987
(出于某种原因,我的解释器首先在第 988 次调用而不是第 1000 次调用时生成错误,但这并没有太大变化。)你可以看到每个错误只会在层次结构中将事情踢回一级,允许整个“嵌套递归”森林。
这导致调用次数呈指数增长。事实上,我通过将递归限制设置为一个小值(我试过 20 和 25)来测试它,并确认递归最终会终止。在我的系统上,它在 2**(R-12)
总调用后终止,其中 R 是递归限制。 (12 是递归限制与实际引发第一个异常的数量之间的差异,如我的示例所示,当第一个异常在 N=988 时引发;大概这 12 个帧在内部以某种方式被“使用”我的翻译。)
您的解释器似乎挂起也就不足为奇了,因为限制为 1000,这将需要比宇宙年龄更长的时间才能完成。
关于python - 为什么这个抛出错误的递归 Python 函数在最后几次调用中来回跳转?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18603764/
来自 java docs 公共(public) FileWriter(String fileName) 抛出 IOException 抛出: IOException - 如果指定的文件存在但它是目录而
我使用以下代码将我的 .net 客户端(基于 CQL)连接到 3 节点 Cassandra 集群。我以 30 条记录/秒的速度(从 RabbitMQ)获取数据,并且它们顺利地存储在 cassandra
如果在读取文件时缺少字段,我应该捕获 NoSuchElementException。如果缺少一个字段,我只需要跳到文件的下一行。我的问题是,我在哪里实现我的 try/catch 代码来做到这一点?这是
我正在尝试使用 ASP.NET MVC 实现 OpeinID 登录。我正在尝试按照 http://blog.nerdbank.net/2008/04/add-openid-login-support-
学习使用 Java 进行 xml 解析,并且正在编写一个测试程序来尝试各种东西。所有测试 System.out.println() 都是我在控制台中所期望的,除了 childElement 返回 [n
我正在尝试使用 SwingUtilities 创建 JFrame Thread tt = new Thread(new Runnable() { public void run
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我写了这段代码: MethodInfo method2 = typeof(IntPtr).GetMethod( "op_Explicit", Bind
我开始学习 Java,并且正在根据书本做一些练习。在执行此操作时,我遇到了以下错误:线程“main”java.util.InputMismatchException 中出现异常。我正在编写一个简单的程
我有一个文本文件,其中前两行是整数 m 和 n,然后有 m 行,每行都有 n 管道分隔值。我编写了一个程序,读取文件并使用文件中的值创建 m*n 数组,它工作了无数次,然后突然,使用相同的代码,使用相
所以我尝试使用在另一个类中生成的 bean 以在主应用程序中使用 package com.simon.spring.basics.properties; import org.spri
我还没有完成这个应用程序,但我希望在我的手机上看到它的样子。但是,它会强制关闭并引发 InstantiationException。 logcat 异常: 09-19 20:13:47.987: D/
我想从 UIViewController 加载一个基于 SwiftUI 的 View ,该 View 读取包本地的 json。仅 swiftUI 项目中的代码和绑定(bind)工作正常,当我利用 UI
'java.net.SocketTimeoutException:连接超时' 循环一段时间后我收到此错误。为什么我会收到 SocketTimeoutException?我该如何修复这个错误? @Ove
当有 null 值时抛出 ArgumentNullException() 是个好主意吗? This thread 没有提到在 null 上抛出的最明显的异常。 谢谢 最佳答案 ArgumentNull
我得到这个异常: NullReferenceException Object reference not set to an instance of an object at Namespace
所以其中一个方法的描述如下: public BasicLinkedList addToFront(T data) This operation is invalid for a sorted list
我正在使用 Intellij Idea,当我去生成 JavaDocs(通过工具 -> 生成 JavaDoc)时,我抛出了一个 IllegealArgumentException,没有关于发生了什么问题
我正在学习 C++ 中的互斥锁,但以下代码(摘自 N. Josuttis 的“C++ 标准库”)有问题。 我不明白为什么它会阻塞/抛出除非我在主线程中添加this_thread::sleep_for(
我正在试验 JavaFX 标签和组,通过鼠标拖动将它们移动到屏幕上。新节点从一些线程添加到动画组。但是,有时我会突然看到以下异常 - 我假设,当某些节点重叠时。但是不知道是什么问题……因为不涉及我的代
我是一名优秀的程序员,十分优秀!