Python 如何将异常推上堆栈?

Python 如何将异常推上堆栈?,python,exception,stack,decorator,stack-trace,Python,Exception,Stack,Decorator,Stack Trace,可能重复: 以这个玩具为例: def twice(n): _validate_twice_args(n) return 2*n def _validate_twice_args(n): if type(n) != int: raise TypeError('n must be an int') twice(None) -- Traceback (most recent call last): File "demo.py", line 9, in

可能重复:

以这个玩具为例:

def twice(n):
    _validate_twice_args(n)
    return 2*n

def _validate_twice_args(n):
    if type(n) != int:
        raise TypeError('n must be an int')

twice(None)
--
Traceback (most recent call last):
  File "demo.py", line 9, in <module>
    twice(None)
  File "demo.py", line 2, in twice
    _validate_twice_args(n)
  File "demo.py", line 7, in _validate_twice_args
    raise TypeError('n must be an int')
TypeError: n must be an int
为了了解这类错误的堆栈跟踪应该是什么样子,下面是一个由非常类似类型的错误导致的跟踪,调用
tweeps()
,而不是
tweeps(None)
,而是在将控制传递给
tweeps
之前由Python引发的跟踪:

Traceback (most recent call last):
  File "demo.py", line 9, in <module>
    twice()
TypeError: twice() takes exactly 1 argument (0 given)
回溯(最近一次呼叫最后一次):
文件“demo.py”,第9行,在
两次
TypeError:tweeps()正好接受1个参数(给定0)
在这种情况下,错误也存在于使用无效参数列表两次调用
。因此,堆栈跟踪直接指向错误的轨迹(谢天谢地,不是指向第一次检测到错误的底层[最有可能的C]代码中的行)。这是应该的,IMO1


如何修改
两次参数
和/或
\u validate\u两次参数
,使堆栈跟踪的最后一行引用对
两次的错误调用的源代码行


1我意识到stacktrace在这种情况下应该说什么的观点与我的不同,但这些哲学上的考虑不是本文的主题。


编辑强调了原始帖子中的评论,但前两位回复者显然忽略了这些评论。

您可以将代码修改为以下内容:

Traceback (most recent call last):
  File "demo.py", line 10, in <module>
    twice(None)
  File "demo.py", line 3, in twice
    raise TypeError('n must be an int')
TypeError: n must be an int
def twice(n):
    error = _validate_twice_args(n)
    if error:
        raise error
    return 2*n

def _validate_twice_args(n):
    if type(n) != int:
        return TypeError('n must be an int')
    return None

twice(None)
这样,错误会从
引发两次。不幸的是,与简单的方法调用相比,它在
方法中需要多一点代码

Traceback (most recent call last):
  File "<module1>", line 28, in <module>
  File "<module1>", line 25, in main
  File "<module1>", line 16, in twice
TypeError: n must be an int
回溯(最近一次呼叫最后一次):
文件“”,第28行,在
文件“”,第25行,主
文件“”,第16行,分两次
TypeError:n必须是整数

您可以将代码修改为以下内容:

Traceback (most recent call last):
  File "demo.py", line 10, in <module>
    twice(None)
  File "demo.py", line 3, in twice
    raise TypeError('n must be an int')
TypeError: n must be an int
def twice(n):
    error = _validate_twice_args(n)
    if error:
        raise error
    return 2*n

def _validate_twice_args(n):
    if type(n) != int:
        return TypeError('n must be an int')
    return None

twice(None)
这样,错误会从
引发两次。不幸的是,与简单的方法调用相比,它在
方法中需要多一点代码

Traceback (most recent call last):
  File "<module1>", line 28, in <module>
  File "<module1>", line 25, in main
  File "<module1>", line 16, in twice
TypeError: n must be an int
回溯(最近一次呼叫最后一次):
文件“”,第28行,在
文件“”,第25行,主
文件“”,第16行,分两次
TypeError:n必须是整数

好吧,您可以将
更改两次:

def twice(n):
    try:
        _validate_twice_args(n)
    except Exception, e:
        raise e
    return 2*n
但是当然,如果您要在
中放置两次try/except块,那么您最好在那里进行实际的签入。当然,这是你真正应该做的,如果你想在那里提出例外,尽管你有脚注。异常发生在发生的地方。您永远不能调用一个函数并期望在该特定函数的实际体中发生任何异常。函数总是调用其他函数。让验证器函数做这样的事情是很好的,但是如果是这样的话,您只需要接受异常将在那里而不是在其他地方出现

作为对编辑的回应:当您在异常发生的地方引发异常时,您可能看起来像是在“公开私有代码”,但以另一种方式进行操作会隐藏错误,这是非常糟糕的。回溯很容易让您查看堆栈,并查找调用函数的位置。然而,按照您所描述的去做会使回溯过高,从而无法看到错误实际发生的位置。若代码可能在其他地方引发异常,那个么有缺陷的代码很容易隐藏自己

更一般地说,你所描述的“错误轨迹”是一种转移注意力的手段。应在检测到异常情况的点引发异常(可能是或可能不是“错误”)。“错误在哪里”是一个更复杂的问题,你不应该试图通过创建“意大利面例外”来掩盖它,而这些例外会在其他地方出现。作为一个人,您可以看到
两次(无)
是这个特定调用链中“犯错误的地方”,但这并不意味着您应该尝试让您的程序变得聪明并让它明白这一点。它可能会在某个时候出错,造成更大的混乱


所以要回答你所强调的:不,你不能那样做。在引发异常的位置引发异常。您不能在一个位置引发异常,并将其显示为在其他位置引发的异常。

好的,您可以将
更改两次,如下所示:

def twice(n):
    try:
        _validate_twice_args(n)
    except Exception, e:
        raise e
    return 2*n
但是当然,如果您要在
中放置两次try/except块,那么您最好在那里进行实际的签入。当然,这是你真正应该做的,如果你想在那里提出例外,尽管你有脚注。异常发生在发生的地方。您永远不能调用一个函数并期望在该特定函数的实际体中发生任何异常。函数总是调用其他函数。让验证器函数做这样的事情是很好的,但是如果是这样的话,您只需要接受异常将在那里而不是在其他地方出现

作为对编辑的回应:当您在异常发生的地方引发异常时,您可能看起来像是在“公开私有代码”,但以另一种方式进行操作会隐藏错误,这是非常糟糕的。回溯很容易让您查看堆栈,并查找调用函数的位置。然而,按照您所描述的去做会使回溯过高,从而无法看到错误实际发生的位置。若代码可能在其他地方引发异常,那个么有缺陷的代码很容易隐藏自己

更一般地说,你所描述的“错误轨迹”是一种转移注意力的手段。应在检测到异常情况的点引发异常(可能是或可能不是“错误”)。“错误在哪里”是一个更复杂的问题,你不应该试图通过创建“意大利面例外”来掩盖它,而这些例外会在其他地方出现。作为一个人,你可以看到
两次(无)
是这个特定呼叫链中“出错的地方”,b