繁体   English   中英

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

[英]Add extra information to all python exceptions

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

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

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__添加空stock以避免此错误可能更明智。

你应该永远不会使用裸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并检查self.stock中的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().")

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM