我想达到这样的效果:
def foo():
try:
raise IOError('Stuff ')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
e.message = e.message + 'happens at %s' % arg1
raise
bar('arg1')
Traceback...
IOError('Stuff Happens at arg1')
但我得到的是:
Traceback..
IOError('Stuff')
关于如何实现这一点,有什么线索吗?如何在Python 2和3中都做到这一点?
我使用的一个方便的方法是使用类属性作为详细信息的存储,因为类属性可以从类对象和类实例中访问:
class CustomError(Exception):
def __init__(self, details: Dict):
self.details = details
然后在代码中:
raise CustomError({'data': 5})
当捕获错误时:
except CustomError as e:
# Do whatever you want with the exception instance
print(e.details)
在PEP 678中,本机支持向异常添加注释:
try:
raise TypeError('bad type')
except Exception as e:
e.add_note('Add some information')
raise
呈现为:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
我跳它可以取代史蒂夫霍华德的解决方案,不幸的是,它不给用户任何控制如何格式化最终的异常(例如,不能在异常之前添加一个注释,如:'错误在fn: {original_exc}')
如果想要对回溯进行更多控制,可以使用https://github.com/google/etils:
from etils import epy
with epy.maybe_reraise('Error in fn: '):
fn()
Or:
try:
fn()
except Exception as e:
epy.reraise(e, suffix='. Did you mean y ?')
到目前为止,我对所有给出的答案都不满意。他们还是太啰嗦了。在代码和消息输出中。
所有我想要的是stacktrace指向源异常,没有异常之间的东西,所以没有创建新的异常,只是重新提升原始与所有相关的堆栈帧状态在它,导致那里。
史蒂夫·霍华德给出了一个很好的答案,我想扩展一下,不,是简化一下……仅适用于python 3。
except Exception as e:
e.args = ("Some failure state", *e.args)
raise
唯一的新东西是参数展开/解包,这使得它对我来说足够小和容易使用。
试一试:
foo = None
try:
try:
state = "bar"
foo.append(state)
except Exception as e:
e.args = ("Appending '"+state+"' failed", *e.args)
raise
print(foo[0]) # would raise too
except Exception as e:
e.args = ("print(foo) failed: " + str(foo), *e.args)
raise
这将给你:
Traceback (most recent call last):
File "test.py", line 6, in <module>
foo.append(state)
AttributeError: ('print(foo) failed: None', "Appending 'bar' failed", "'NoneType' object has no attribute 'append'")
简单的漂亮图案可以是这样的
print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
与之前的答案不同,这适用于非常糟糕的__str__异常。
但是,它确实修改了类型,以便剔除无用的__str__实现。
我仍然希望找到一个不修改类型的额外改进。
from contextlib import contextmanager
@contextmanager
def helpful_info():
try:
yield
except Exception as e:
class CloneException(Exception): pass
CloneException.__name__ = type(e).__name__
CloneException.__module___ = type(e).__module__
helpful_message = '%s\n\nhelpful info!' % e
import sys
raise CloneException, helpful_message, sys.exc_traceback
class BadException(Exception):
def __str__(self):
return 'wat.'
with helpful_info():
raise BadException('fooooo')
原始的回溯和类型(名称)被保留。
Traceback (most recent call last):
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
File "/usr/lib64/python2.6/contextlib.py", line 34, in __exit__
self.gen.throw(type, value, traceback)
File "re_raise.py", line 5, in helpful_info
yield
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
__main__.BadException: wat.
helpful info!