2016-02-10 90 views
0

考慮下面的示例類中的Python:Python的析構函數失敗構造

class MyClass: 
    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 
在測試套件

,我想檢查時調用構造函數不帶參數拋出一個異常,即:

c = MyClass() 

有了這個,我得到預期的異常從構造函數:

Traceback (most recent call last): 
    File ".../example.py", line 9, in <module> 
    c = MyClass() 
TypeError: __init__() missing 1 required positional argument: 'obj' 

然而,析構函數也將失敗與消息:

Exception ignored in: <bound method MyClass.__del__ of <__main__.MyClass object at 0x0000023D1211CD30>> 
Traceback (most recent call last): 
    File ".../example.py", line 6, in __del__ 
    if self._obj: 
AttributeError: 'MyClass' object has no attribute '_obj' 

據推測,這是因爲構造函數沒有被調用,因爲有一種說法缺少的,因此永遠不會創建的屬性。

解決這個問題的正確方法是什麼?

+0

你有沒有一個抽象的例子?如果你真的想要安全,可以使用'getattr'或'try'屬性訪問。 – jonrsharpe

+1

Python沒有析構函數。它確實有終結者。通常,做事的正確方法是避免完全使用它們。 –

+0

值得注意的是'__del__'中產生的異常被忽略。 – Blckknght

回答

2

測試該屬性是否實際設置,也通過使其成爲類屬性來提供默認值。

例如,設置類屬性,使你當前的代碼工作:

class MyClass: 
    _obj = None # class attribute 

    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 

或使用getattr()帶有默認:

def __del__(self): 
    if getattr(self, '_obj', None): 
     print(self._obj) 

返回的第三個參數,如果屬性不存在。

+0

這是否意味着'self._obj = obj'行會用一個實例替換class屬性? – Nzbuu

+0

不替代,沒有。實例屬性*掩碼*類屬性,因爲Python首先在實例上查找屬性,然後是類,然後是基類。 –

+0

啊,好的。這更有意義。謝謝。 – Nzbuu

1

您可以使用一個類屬性:

class MyClass(object): 
    _obj = None 

    def __init__(self, obj): 
     self._obj = obj 

    def __del__(self): 
     if self._obj: 
      print(self._obj) 

這樣,總有一個默認的(falsy)值(如果該實例查找失敗,類查詢會成功)。

就這樣說,__del__在python中就像是一隻黑羊。一般來說,建議是「不要使用它」的原因有很多。上下文管理器通常是一個稍微更明確的替代品(儘管它們不涵蓋所有用例)。