将信息添加到exception?

编辑:我正在运行Python 2.6

我想实现这样的事情:

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') 

任何线索,如何实现这一目标?

我会这样做,所以在foo()改变它的types也不需要在bar()改变它。

 def foo(): try: raise IOError('Stuff') except: raise def bar(arg1): try: foo() except Exception as e: raise type(e)(e.message + ' happens at %s' % arg1) bar('arg1') 
 Traceback (most recent call last): File "test.py", line 13, in <module> bar('arg1') File "test.py", line 11, in bar raise type(e)(e.message + ' happens at %s' % arg1) IOError: Stuff happens at arg1 

更新1

这是一个稍微的修改,保留了原始的回溯:

 ... def bar(arg1): try: foo() except Exception as e: import sys raise type(e), type(e)(e.message + ' happens at %s' % arg1), sys.exc_info()[2] bar('arg1') 
 Traceback (most recent call last): File "test.py", line 16, in <module> bar('arg1') File "test.py", line 11, in bar foo() File "test.py", line 5, in foo raise IOError('Stuff') IOError: Stuff happens at arg1 

更新2

对于Python 3.x,我的第一次更新中的代码在语法上是不正确的,加上在BaseException上拥有一个message属性的想法在BaseException被更改为PEP 352 (我的第一个更新发布在2012-03- 12)。 因此,目前在Python 3.5.2中,你需要沿着这些线做一些事情来保留回溯,而不是在函数bar()硬编码exception的types。 还要注意会有这样一行:

 During handling of the above exception, another exception occurred: 

在显示的回溯信息中。

 # for Python 3.x ... def bar(arg1): try: foo() except Exception as e: import sys raise type(e)(str(e) + ' happens at %s' % arg1).with_traceback(sys.exc_info()[2]) bar('arg1') 

更新3

一位评论者问,是否有一种方法可以在Python 2和Python 3中工作。虽然由于语法的不同,答案似乎是“否”,但是通过使用像reraise()这样的辅助函数可以解决这个问题。 six附加模块。 所以,如果你不想使用库,下面是一个简化的独立版本。

还要注意的是,由于在reraise reraise()函数内reraise()了exception,所以会出现在所有引发的回溯中,但最终的结果是你想要的。

 import sys if sys.version_info.major < 3: # Python 2? # Using exec avoids a SyntaxError in Python 3. exec("""def reraise(exc_type, exc_value, exc_traceback=None): raise exc_type, exc_value, exc_traceback""") else: def reraise(exc_type, exc_value, exc_traceback=None): if exc_value is None: exc_value = exc_type() if exc_value.__traceback__ is not exc_traceback: raise exc_value.with_traceback(exc_traceback) raise exc_value def foo(): try: raise IOError('Stuff') except: raise def bar(arg1): try: foo() except Exception as e: reraise(type(e), type(e)(str(e) + ' happens at %s' % arg1), sys.exc_info()[2]) bar('arg1') 

假设你不想或不能修改foo(),你可以试试这个:

 try: raise IOError('stuff') except Exception as e: e.args = (e.args[0] + ' happens',) raise 

如果你来这里寻找Python3 的解决scheme, 手册上说:

当引发一个新的exception(而不是使用裸raise来重新引发当前正在处理的exception)时,隐式的exception上下文可以用一个明确的原因来补充:

 raise new_exc from original_exc 

例:

  try: return [permission() for permission in self.permission_classes] except TypeError as e: raise TypeError("Make sure your view's 'permission_classes' are iterable. " +"If you use '()' to generate a set with a single element " +"make sure that there is a comma behind the one (element,).") from e 

最后看起来像这样:

  2017-09-06 16:50:14,797 [ERROR] django.request: Internal Server Error: /v1/sendEmail/ Traceback (most recent call last): File "venv/lib/python3.4/site-packages/rest_framework/views.py", line 275, in get_permissions return [permission() for permission in self.permission_classes] TypeError: 'type' object is not iterable The above exception was the direct cause of the following exception: Traceback (most recent call last): # Traceback removed... TypeError: Make sure your view's Permission_classes are iterable. If you use parens () to generate a set with a single element make sure that there is a (comma,) behind the one element. 

把一个完全不重要的TypeError变成一个很好的消息,提示一个解决scheme,而不会搞乱原始exception。

你可以定义你自己的exceptioninheritance另一个exception,并创build它自己的构造函数来设置值。

例如:

 class MyError(Exception): def __init__(self, value): self.value = value Exception.__init__(self) def __str__(self): return repr(self.value) 

我使用的一个方便的方法是使用类属性作为存储的细节,因为类属性可以从类对象和类实例访问:

 class CustomError(Exception): details = None 

然后在你的代码中:

 exc = CustomError('Some message') exc.details('Details -- add whatever you want') raise exc 

当遇到一个错误:

 except CustomError, e: # Do whatever you want with the exception instance print e print e.details 

与以前的答案不同,这个工作面对的是非常糟糕的__str__exception。 但是,它修改types,以便__str__无用的__str__实现。

我仍然希望find一个不会修改types的额外改进。

 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') 

原始回溯和types(名称)被保留。

 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! 

我会提供一段代码,我经常使用,只要我想添加额外的信息到exception。 我在Python 2.7和3.6中工作。

 import sys import traceback try: a = 1 b = 1j # The line below raises an exception because # we cannot compare int to complex. m = max(a, b) except Exception as ex: # I create my informational message for debugging: msg = "a=%r, b=%r" % (a, b) # Gather the information from the original exception: exc_type, exc_value, exc_traceback = sys.exc_info() # Format the original exception for a nice printout: traceback_string = ''.join(traceback.format_exception( exc_type, exc_value, exc_traceback)) # Re-raise a new exception of the same class as the original one, # using my custom message and the original traceback: raise type(ex)("%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % (msg, traceback_string)) 

上面的代码产生以下输出:

 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-6-09b74752c60d> in <module>() 14 raise type(ex)( 15 "%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % ---> 16 (msg, traceback_string)) TypeError: a=1, b=1j ORIGINAL TRACEBACK: Traceback (most recent call last): File "<ipython-input-6-09b74752c60d>", line 7, in <module> m = max(a, b) # Cannot compare int to complex TypeError: no ordering relation is defined for complex numbers 

我知道这个问题与这个问题提供的例子稍有不同,但我希望有人发现它有用。

也许

 except Exception as e: raise IOError(e.message + 'happens at %s'%arg1)