使用自定义属性重新引发异常的python3 re-raising?

7

这是我来自 Python 2 的代码,需要移植:

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

通过以上代码,我可以通过检查异常是否具有“filename”属性来获取由有问题的输入文件引起的整个异常。

然而,Python3的raise已经改变。以下是2to3为上述代码提供的内容:

except Exception as e:
  et, ei, tb = sys.exc_info()
  e.filename = filename
  raise et(e).with_traceback(tb)

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

in __call__
    raise et(e).with_traceback(tb)
TypeError: function takes exactly 5 arguments (1 given)

我想要的是能够透明地传递异常,并附带一些信息以跟踪输入文件。我错过了Python2中的raise [exception_type[,exception_instance[,traceback]]] - 在Python3中应该如何实现?

2个回答

6
你可以设置 __traceback__ 属性:
except Exception as e:
    et, ei, tb = sys.exc_info()
    ei.filename = filename
    ei.__traceback__ = tb
    raise ei

或者直接在旧实例上调用.with_traceback()
except Exception as e:
    et, ei, tb = sys.exc_info()
    ei.filename = filename
    raise ei.with_traceback(tb)

然而,回溯已经自动附加,没有必要重新附加,真的不需要。
请参阅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

这将创建一个链式异常,在未捕获时将打印两个异常,并且可以通过 newexception.__context__ 访问原始异常。


谢谢!但我刚刚在Google上找到了raise ei.with_traceback(tb) :D - thkang
@thkang:请参阅http://docs.python.org/3/reference/simple_stmts.html#the-raise-statement,两者都是有效的。 - Martijn Pieters
谢谢,我认为最好的想法是使用Python3的raise ... from ...风格重新编写每个异常处理代码。 - thkang
只要您创建一个新的异常,from语法就非常好。 - Martijn Pieters

6

你不需要做任何事情;在Python 3中,重新引发的异常会自动具有完整的回溯信息,说明它们最初是从哪里引发的。

try:
  do_something_with_file(filename)
except Exception as exc_inst:
  exc_inst.filename = filename
  raise exc_inst

这是有效的,因为在except语句中捕获异常时,PyErr_NormalizeException会适当地设置__traceback__属性; 请参见http://www.python.org/dev/peps/pep-3134/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接