【发布时间】:2012-01-06 17:25:07
【问题描述】:
短版:
有没有办法在 Python 中实现与 Perl 的
@987654321@实用程序相同的效果?
长版(对于不熟悉Carp::carp的人):
假设我们正在实现一些库 API 函数(即,它旨在供其他程序员在他们的代码中使用),比如spam,并假设spam 包含一些代码检查传递给它的参数的有效性。当然,如果检测到这些参数有任何问题,这段代码应该引发异常。假设我们想让相关的错误消息和回溯对调试某些客户端代码的人尽可能有用。
理想情况下,此引发的异常产生的回溯的最后一行应查明“违规代码”,即客户端代码中使用无效参数调用spam 的行。 p>
不幸的是,至少在默认情况下,使用 Python 不会发生这种情况。相反,回溯的最后一行将引用库代码内部的某个地方,其中异常实际上是 raise'd,这对于 this 特定的目标受众来说是非常模糊的追溯。
例子:
# spam.py (library code)
def spam(ham, eggs):
'''
Do something stupid with ham and eggs.
At least one of ham and eggs must be True.
'''
_validate_spam_args(ham, eggs)
return ham == eggs
def _validate_spam_args(ham, eggs):
if not (ham or eggs):
raise ValueError('if we had ham '
'we could have ham and eggs '
'(if we had eggs)')
# client.py (client code)
from spam import spam
x = spam(False, False)
当我们运行 client.py 时,我们得到:
% python client.py
Traceback (most recent call last):
File "client.py", line 3, in <module>
x = spam(False, False)
File "/home/jones/spam.py", line 7, in spam
_validate_spam_args(ham, eggs)
File "/home/jones/spam.py", line 12, in _validate_spam_args
raise ValueError('if we had ham '
ValueError: if we had ham we could have ham and eggs (if we had eggs)
而我们想要的更接近:
% python client.py
Traceback (most recent call last):
File "client.py", line 3, in <module>
x = spam(False, False)
ValueError: if we had ham we could have ham and eggs (if we had eggs)
...将违规代码 (x = spam(False, False)) 作为回溯的最后一行。
我们需要的是某种“从调用者的角度”报告错误的方法(这是Carp::carp 允许人们在 Perl 中做的事情)。
编辑:为了清楚起见,这个问题不是关于 LBYL 与 EAFP,也不是关于先决条件或按合同编程。如果我给了这个错误的印象,我很抱歉。这个问题是关于如何从调用堆栈的几个(一、二)级开始产生回溯。
EDIT2:Python 的 traceback 模块显然是寻找与 Perl 的 Carp::carp 等效的 Python 的地方,但在研究了一段时间后,我无法找到任何方法将它用于我想要的做。 FWIW,Perl 的Carp::carp 允许通过公开全局(因此动态范围)变量$Carp::CarpLevel 来微调回溯的初始帧。可能carp-out、local-ize 并在输入时增加此变量的非 API 库函数(例如 local $Carp::CarpLevel += 1;)。我没有看到任何类似 Python 的 traceback 模块的东西甚至是远程。因此,除非我错过了什么,否则任何使用 Python 的 traceback 的解决方案都必须采取完全不同的策略......
【问题讨论】:
标签: python stack-trace callstack