为所有python异常添加额外信息

在又一次可怕的虫子追捕之后,我想知道以下内容:
是否可以向所有异常添加一些额外信息,例如对象的名称.
这会大大增加错误的可读性,并且可以更快地查找错误(或输入错误).如果有多个对象来自同一个类并因此共享很多代码但具有不同的属性,则尤其如此.在这种情况下,如果错误消息还指出错误中对象的名称,则它非常有用.

一个简单的例子:我正在尝试模拟不同类型的设施,养猪场和奶牛场.这些是同一个类,但确实有不同的属性.在模拟中,会创建许多工具,如果引发异常,如果将对象的名称添加到异常中将非常有用.

class facility():
    def __init__(self, name):
        self.name = name
        self.animals = []

farms = []
farms.append(facility('cow_farm'))
farms.append(facility('pig_farm'))
print farms[0].stock

这会产生

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: facility instance has no attribute 'stock'

但我想添加设施的名称:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: facility instance has no attribute 'stock'
  Name of object: cow_farm

我试过类似的东西

def print_name(exception):
    try:
        print self.name
    except AttributeError:
        pass
    raise exception

@print_name
Exception

但这不起作用.有可能做这样的事情,还是有充分的理由不这样做?

解决方法:

如果要处理错误并添加信息,可以按如下方式执行:

farm = farms[0]
try:
    print farm.stock
except AttributeError:
    raise AttributeError("{} has no attribute 'stock'".format(farm.name))

但是,在__init__中添加空库存以避免此错误可能更明智.

你应该never use a bare except,因为它隐藏了你的有用信息(特别是在开发和调试时!)通常,每个try块应该尽可能短,最好只做一件事.如果多个错误可能来自单个try块,则可以添加多个处理程序:

try:
    print farm.stock["hay"]
except AttributeError:
    raise AttributeError("{} has no attribute 'stock'".format(farm.name))
except KeyError:
    raise KeyError("{} has no 'hay' in 'stock'".format(farm.name))

(虽然请注意在__init__中添加self.stock并检查farm.stock中的“hay”是否会使您免于此错误处理.)

如果发生了您不期望的错误,通常最好将该错误传播到调用堆栈,直到它被明确处理或您看到它.否则,你正在走向这个愚蠢的反模式:

def some_func(*args, **kwargs):
    try:
        # all of some_func's content goes here
    except:
        raise Exception("Something went wrong in some_func().")

这对你没用,对于任何试图使用你的代码的人来说都是非常令人沮丧的.

如果你想在类级别处理这样的AttributeErrors,你可以这样做:

class Facility(object):

    def __init__(self, ...):
        ...

    def __getattr__(self, key):
        """Called on attempt to access attribute instance.key."""
        if key not in self.__dict__:
            message = "{} instance '{}' has no attribute '{}'."
            message = message.format(type(self).__name__,
                                     self.name, key)
            raise AttributeError(message)
        else:
            return self.__dict__[key]

然后你会得到

>>> farm = Facility("pig farm")
>>> print farm.stock
...
"AttributeError: Facility instance 'pig farm' has no attribute 'stock'."

如果要将此模式与多个类一起使用,可以创建一个超类:

class ProtectedAttrs(object):

    def __init__(self, name):
        self.name = name

    def __getattr__(self, key):
        ...

class Facility(ProtectedAttrs):

    def __init__(self, name):
        super(Facility, self).__init__(name)
        self.animals = []

这种事情适用于某些类型的错误.但是,我不知道通过引用所涉及的实例来处理所有错误的任何一般方法.

上一篇:(python)在函数中使用装饰器进行彩色打印


下一篇:详解Spring中的9种设计模式「记得收藏」