gpt4 book ai didi

python - "Uncatching"python中的异常

转载 作者:IT老高 更新时间:2023-10-28 20:53:12 25 4
gpt4 key购买 nike

我应该如何“重新抛出”异常,即假设:

  • 我在我的代码中尝试了一些东西,但不幸的是它失败了。
  • 我尝试了一些“聪明”的解决方法,但这次也失败了

如果我从(失败的)解决方法中抛出异常,用户会非常困惑,所以我认为最好重新抛出原始异常 (?),< em>带有描述性回溯(关于实际问题)...

注意:这方面的激励示例是在调用 np.log(np.array(['1'], dtype=object)) 时,它是 tries a witty workaround and gives an AttributeError (它“真的”是一个 TypeError)。

我能想到的一种方法是重新调用有问题的函数,但这似乎是顽固的(一方面,理论上原始函数在第二次调用时可能会表现出一些不同的行为):
好吧,这是一个糟糕的例子,但这里是……

def f():
raise Exception("sparrow")

def g():
raise Exception("coconut")

def a():
f()

假设我这样做了:

try:
a()
except:
# attempt witty workaround
g()
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-4-c76b7509b315> in <module>()
3 except:
4 # attempt witty workaround
----> 5 g()
6

<ipython-input-2-e641f2f9a7dc> in g()
4
5 def g():
----> 6 raise Exception("coconut")
7
8

Exception: coconut

嗯,问题根本不在于椰子,而在于麻雀:

try:
a()
except:
# attempt witty workaround
try:
g()
except:
# workaround failed, I want to rethrow the exception from calling a()
a() # ideally don't want to call a() again
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-4-e641f2f9a7dc> in <module>()
19 except:
20 # workaround failed, I want to rethrow the exception from calling a()
---> 21 a() # ideally don't want to call a() again

<ipython-input-3-e641f2f9a7dc> in a()
8
9 def a():
---> 10 f()
11
12

<ipython-input-1-e641f2f9a7dc> in f()
1 def f():
----> 2 raise Exception("sparrow")
3
4
5 def g():

Exception: sparrow

有没有标准的方法来处理这个问题,还是我认为它完全错误?

最佳答案

如果您想让最终用户觉得您从未调用过 g(),那么您需要存储第一个错误的回溯,调用第二个函数,然后抛出原始错误与原始回溯。 (否则,在 Python2 中,bare raise 会重新引发第二个异常而不是第一个)。问题是没有 2/3 兼容的方式来引发回溯,因此您必须将 Python 2 版本包装在 exec 语句中(因为它是一个 SyntaxError 在Python 3)。

这是一个可以让你做到这一点的函数(我最近将它添加到 pandas 代码库中):

import sys
if sys.version_info[0] >= 3:
def raise_with_traceback(exc, traceback=Ellipsis):
if traceback == Ellipsis:
_, _, traceback = sys.exc_info()
raise exc.with_traceback(traceback)
else:
# this version of raise is a syntax error in Python 3
exec("""
def raise_with_traceback(exc, traceback=Ellipsis):
if traceback == Ellipsis:
_, _, traceback = sys.exc_info()
raise exc, None, traceback
""")

raise_with_traceback.__doc__ = (
"""Raise exception with existing traceback.
If traceback is not passed, uses sys.exc_info() to get traceback."""
)

然后你可以像这样使用它(为了清楚起见,我还更改了异常类型)。

def f():
raise TypeError("sparrow")

def g():
raise ValueError("coconut")

def a():
f()

try:
a()
except TypeError as e:
import sys
# save the traceback from the original exception
_, _, tb = sys.exc_info()
try:
# attempt witty workaround
g()
except:
raise_with_traceback(e, tb)

而在 Python 2 中,您只能看到 a()f():

Traceback (most recent call last):
File "test.py", line 40, in <module>
raise_with_traceback(e, tb)
File "test.py", line 31, in <module>
a()
File "test.py", line 28, in a
f()
File "test.py", line 22, in f
raise TypeError("sparrow")
TypeError: sparrow

但在 Python 3 中,它仍然注意到还有一个额外的异常,因为您在其 except 子句中引发 [这会颠倒错误的顺序并使用户更加困惑]:

Traceback (most recent call last):
File "test.py", line 38, in <module>
g()
File "test.py", line 25, in g
raise ValueError("coconut")
ValueError: coconut

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "test.py", line 40, in <module>
raise_with_traceback(e, tb)
File "test.py", line 6, in raise_with_traceback
raise exc.with_traceback(traceback)
File "test.py", line 31, in <module>
a()
File "test.py", line 28, in a
f()
File "test.py", line 22, in f
raise TypeError("sparrow")
TypeError: sparrow

如果你绝对希望它看起来像 g() 异常在 Python 2 和 Python 3 中都没有发生,你需要检查你是否在 except 子句第一:

try:
a()
except TypeError as e:
import sys
# save the traceback from the original exception
_, _, tb = sys.exc_info()
handled = False
try:
# attempt witty workaround
g()
handled = True
except:
pass
if not handled:
raise_with_traceback(e, tb)

在 Python 2 中为您提供以下回溯:

Traceback (most recent call last):
File "test.py", line 56, in <module>
raise_with_traceback(e, tb)
File "test.py", line 43, in <module>
a()
File "test.py", line 28, in a
f()
File "test.py", line 22, in f
raise TypeError("sparrow")
TypeError: sparrow

Python 3 中的这个追溯:

Traceback (most recent call last):
File "test.py", line 56, in <module>
raise_with_traceback(e, tb)
File "test.py", line 6, in raise_with_traceback
raise exc.with_traceback(traceback)
File "test.py", line 43, in <module>
a()
File "test.py", line 28, in a
f()
File "test.py", line 22, in f
raise TypeError("sparrow")
TypeError: sparrow

它确实添加了一个额外的无用的回溯行,向用户显示 raise exc.with_traceback(traceback),但它相对干净。

关于python - "Uncatching"python中的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17001473/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com