2

假设我有以下脚本:

def do_not_call_on_one(i):
    if i == 1:
        raise ValueError("You never listen.")

    print "Success!"

do_not_call_on_one(1)

在执行时,您将看到以下回溯:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    do_not_call_on_one(1)
  File "test.py", line 3, in do_not_call_on_one
    raise ValueError("You never listen.")
ValueError: You never listen.

是否有某种方法可以操纵调用堆栈,以便从实际导致问题的行发出错误,就像这样?:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    do_not_call_on_one(1)
ValueError: You never listen.

当可以提前定义正确的行为时,这将节省开发人员的时间,否则这些时间会浪费在扫描调用堆栈、搜索错误使用的函数上。

Python中有什么东西可以允许异常使用修改后的回溯吗?

更新

有一些 buitins 正在复制此功能:

# In test.py:
int('a')

# Executing 'python test.py' yields:
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    int('a')
ValueError: invalid literal for int() with base 10: 'a'

注意:回溯不会下降到int()函数中以显示一堆无用的范围(尤其是无用的范围raise ValueError本身)。

4

2 回答 2

3

tl; dr:可能是的,但我无法想象这是一个好主意。

我假设如果我们足够努力,我们可以伪造一个调用堆栈来显示来自不同地方的异常。但我不认为这是一个好主意。

首先,人们普遍认为引发异常的函数并不总是有错误的。如果有人违反合同并向您传递了您不期望的参数,则可以引发异常。如果这是为了通过在调用者的范围内引发异常来掩盖你的屁股,那么没有人会责怪你的功能,我认为有人(也许是你,也许是你的自动化测试的“责备”系统)需要重新考虑他们如何确定责任。

其次,我认为您不能很好地定义“正确”范围。您可能会认为它应该始终在调用者的范围内提出,因为显然这不是您的错。好吧,如果这也不是他们的错呢?当异常发生时,每个函数都应该举手并说“不是我的错”吗?很快我们的堆栈跟踪将什么也不说。

即使你是对的,并且你的函数是无可指责的,你也会让其他人的生活陷入困境,因为操纵调用堆栈来隐藏你的函数会让每个人都摸不着头脑,并删除调试情况的有价值的证据。

这似乎是一个好主意,但我认为不是,而且我认为如果你设身处地为他人着想,你就会明白尝试使用这种行为方式的功能会让他们的生活变得多么困难。

于 2013-06-20T20:48:49.900 回答
1

我建议在您希望位于调用堆栈顶部的位置捕获异常,然后引发一个包装旧异常的新异常(以便您可以参考原始调用堆栈以了解实际导致问题的异常;之后所有,当print "Success!"失败时会发生什么,例如,有人设置sys.stdout = int?)。


经过一番浏览,似乎https://stackoverflow.com/a/2615442/138772正是您想要的那种答案。

于 2013-06-20T20:47:41.740 回答