簡體   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