python3使用自定义属性重新引发异常?

thk*_*ang 7 python python-3.x

这是我需要移植的python2代码:

try:
  do_something_with_file(filename)

except:
  exc_type, exc_inst, tb = sys.exc_info()
  exc_inst.filename = filename
  raise exc_type, exc_inst, tb
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,我可以通过检查异常是否具有'filename'属性来获取有问题的输入文件的整个异常.

但是python3的加注已经改变了.这是2to3给我的上述代码:

except Exception as e:
  et, ei, tb = sys.exc_info()
  e.filename = filename
  raise et(e).with_traceback(tb)
Run Code Online (Sandbox Code Playgroud)

这给了我另一个错误,我不认为文件名属性被保留:

in __call__
    raise et(e).with_traceback(tb)
TypeError: function takes exactly 5 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

我只想要透明地传递异常和一些信息来跟踪输入文件.我想念python2 raise [exception_type[,exception_instance[,traceback]]]- 我怎么能在python3中做到这一点?

Mar*_*ers 6

您可以设置__traceback__属性:

except Exception as e:
    et, ei, tb = sys.exc_info()
    ei.filename = filename
    ei.__traceback__ = tb
    raise ei
Run Code Online (Sandbox Code Playgroud)

或者.with_traceback()直接在旧实例上调用:

except Exception as e:
    et, ei, tb = sys.exc_info()
    ei.filename = filename
    raise ei.with_traceback(tb)
Run Code Online (Sandbox Code Playgroud)

但是,回溯已经自动附加,没有必要重新附加它,真的.

请参阅raise声明文档:

通常会在引发异常时自动创建回溯对象,并将其作为__traceback__属性附加到该属性,该属性是可写的.

在这个特定的情况下,也许您想要一个不同的异常,而不是上下文?

class FilenameException(Exception):
    filename = None
    def __init__(self, filename):
        super().__init__(filename)
        self.filename = filename

try:
    something(filename)
except Exception as e:
    raise FilenameException(filename) from e
Run Code Online (Sandbox Code Playgroud)

这将创建一个链式异常,如果未捕获则会打印两个异常,并且原始异常可用newexception.__context__.


eca*_*mur 5

您无需执行任何操作;在Python 3中,重新引发的异常会自动从原始引发的位置进行完整的追溯。

try:
  do_something_with_file(filename)
except Exception as exc_inst:
  exc_inst.filename = filename
  raise exc_inst
Run Code Online (Sandbox Code Playgroud)

之所以起作用,是因为在捕获语句中的异常时适当地PyErr_NormalizeException设置了__traceback__属性except;参见http://www.python.org/dev/peps/pep-3134/