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

时间:2014-01-02 10:59:01

标签: python oop exception exception-handling decorator

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

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

但是,在stock中添加空__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))

(尽管请注意,在self.stock中添加__init__并检查if "hay" in farm.stock:可以避免此错误处理。)

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

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

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

如果您想在AttributeError级别处理class这样的问题,您可以这样做:

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 = []

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

答案 1 :(得分:-1)

大多数例外都包含 message 属性,可以为您提供有关错误的其他信息

In [163]: try:
   .....:     farm = []
   .....:     farm.stock
   .....: except AttributeError as err:
   .....:     print err.message
   .....:     
'list' object has no attribute 'stock'

异常回溯将您指向代码行,因此通常不难发现问题