将信息添加到例外?

ani*_*haw 116 python 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')
Run Code Online (Sandbox Code Playgroud)
Traceback...
  IOError('Stuff Happens at arg1')
Run Code Online (Sandbox Code Playgroud)

但我得到的是:

Traceback..
  IOError('Stuff')
Run Code Online (Sandbox Code Playgroud)

关于如何实现这一点的任何线索?

mar*_*eau 103

我会这样做,所以改变它的类型foo()将不需要也改变它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')
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

更新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')
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

更新2

对于Python 3.x,我的第一次更新中的代码在语法上是不正确的,加上在2012-05-16 更改为PEP 352收回message属性的想法(我的第一次更新发布于2012-03-12) .所以目前,无论如何,在Python 3.5.2中,您需要沿着这些行做一些事情以保留回溯,而不是在函数中硬编码异常类型.另请注意,会有一行:BaseExceptionbar()

During handling of the above exception, another exception occurred:
Run Code Online (Sandbox Code Playgroud)

在显示的追溯消息中.

# 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')
Run Code Online (Sandbox Code Playgroud)

更新3

一个评论者询问是否有会在两个Python 2和3.工作虽然答案可能似乎是"不",因为语法不同的方式,还有就是周围的一种方法,通过使用一个辅助函数一样reraise()six添加-在模块上.因此,如果您因某些原因而不想使用该库,则下面是一个简化的独立版本.

另请注意,由于异常在reraise()函数内被重新启动,因此会出现在引发的任何回溯中,但最终结果是您想要的.

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')
Run Code Online (Sandbox Code Playgroud)

  • 失去了回溯,有点打败了向现有异常添加信息的重点.此外,它不会使用带有> 1个参数的ctor的异常(类型是您无法从捕获异常的位置控制的类型). (3认同)

Chr*_*ris 76

如果您来到这里寻找Python3 解决方案,手册 说:

在引发新异常时(而不是使用bare raise来重新引发当前正在处理的异常),可以通过使用from with raise来使用明确的原因来补充隐式异常上下文:

raise new_exc from original_exc
Run Code Online (Sandbox Code Playgroud)

例:

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
Run Code Online (Sandbox Code Playgroud)

最终看起来像这样:

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.
Run Code Online (Sandbox Code Playgroud)

将完全不起眼的TypeError转换为带有提示解决方案的好消息,而不会弄乱原始异常.

  • 这是最好的解决方案,因为产生的异常指向原始原因,提供更多细节. (8认同)
  • 有什么解决方案可以添加一些消息但仍然不会引发新的异常吗?我的意思是只是扩展异常实例的消息。 (2认同)

Con*_*tor 28

PEP 678 (Python 3.11) 原生支持向异常添加注释:

try:
  raise TypeError('bad type')
except Exception as e:
  e.add_note('Add some information')
  raise
Run Code Online (Sandbox Code Playgroud)

渲染为:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
Run Code Online (Sandbox Code Playgroud)

我希望它可以取代Steve Howard 解决方案,不幸的是,它没有为用户提供有关如何格式化最终异常的任何控制(例如,无法在异常之前添加注释,例如'Error in fn: {original_exc}':)

如果您想对回溯进行更多控制,可以使用https://github.com/google/etils

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
Run Code Online (Sandbox Code Playgroud)

或者:

from etils import epy

with epy.maybe_reraise('Error in fn: '):
  fn()
Run Code Online (Sandbox Code Playgroud)

  • PEP 678 [刚刚被接受](https://discuss.python.org/t/pep-678-enriching-exceptions-with-notes/13374/100) (3认同)

Ste*_*ard 21

假设您不想或不能修改foo(),您可以这样做:

try:
    raise IOError('stuff')
except Exception as e:
    if len(e.args) >= 1:
        e.args = (e.args[0] + ' happens',) + e.args[1:]
    raise
Run Code Online (Sandbox Code Playgroud)

这确实是解决Python 3中的问题的唯一解决方案,没有丑陋和令人困惑的"在处理上述异常时,发生了另一个异常"消息.

如果应该将重新上升线添加到堆栈跟踪中,则写入raise e而不是raise执行操作.

  • 更完整/合作,包括原始元组的其他部分:`e.args =('mynewstr'+ e.args [0],)+ e.args [1:]` (5认同)

6EQ*_*UJ5 14

到目前为止,我不喜欢所有给出的答案。他们仍然过于冗长恕我直言。在代码和消息输出中。

我想要的只是指向源异常的堆栈跟踪,中间没有异常的东西,所以没有创建新的异常,只需重新提升原始的所有相关堆栈帧状态,就可以了。

史蒂夫霍华德给出了一个很好的答案,我想扩展,不,减少......仅适用于python 3。

except Exception as e:
    e.args = ("Some failure state", *e.args)
    raise
Run Code Online (Sandbox Code Playgroud)

唯一的新东西是参数扩展/解包,这使得它足够小且易于使用。

尝试一下:

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
Run Code Online (Sandbox Code Playgroud)

这会给你:

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'")
Run Code Online (Sandbox Code Playgroud)

一个简单的漂亮印刷品可能是这样的

print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
Run Code Online (Sandbox Code Playgroud)


Kee*_*Kee 6

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

class CustomError(Exception):
    def __init__(self, details: Dict):
        self.details = details
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中:

raise CustomError({'data': 5})
Run Code Online (Sandbox Code Playgroud)

当捕获错误时:

except CustomError as e:
    # Do whatever you want with the exception instance
    print(e.details)
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

57292 次

最近记录:

6 年,2 月 前