我想达到这样的效果:

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中都做到这一点?


当前回答

我在代码中使用:

try:
    a=1
    b=0
    c=a/b

except:
    raise Exception(f"can't divide {a} with {b}")

输出:

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_11708/1469673756.py in <module>
      3     b=0
----> 4     c=a/b
      5 

ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Exception                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_11708/1469673756.py in <module>
      5 
      6 except Exception:
----> 7     raise Exception(f"can't divide {a} with {b}")

Exception: can't divide 1 with 0

其他回答

您可以定义从另一个异常继承的自己的异常,并创建它自己的构造函数来设置值。

例如:

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

   def __str__(self):
     return repr(self.value)

也许

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

以下是我在个人项目中使用的方法(我相信有足够的理由不在产品代码中这样做):

try:
    #something hazardous
except Exception as e:
    insightful_message = "shouldn't have done that"
    amended_args = tuple([f'{e.args[0]}\n{insightful_message}', *e.args[1:]])
    e.args = amended_args
    raise

代码(1)拦截错误;(2)创建错误的.args属性的副本,这是一个元组,假定在索引0处包含一个错误消息,使用列表理解实现;(3)在错误消息后追加换行符和自定义消息;(4)使用。args附加到副本的任何附加项 拆包;(5)将副本转换为元组;最后(6)用修改后的副本替换。args。

这些操作大多是为了避免.args元组的不可变性。

我将提供一段我经常使用的代码片段,每当我想向异常添加额外信息时。我在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


我知道这与问题中提供的例子有一点偏差,但我希望有人觉得它有用。

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

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)