2014-01-15 57 views
3

我正在嘗試使用靜態列表來創建一個類,它收集對象類的所有新實例。我面臨的問題,似乎只要我嘗試像使用整數一樣使用列表,我不能再使用神奇標記__del__Python靜態變量列表__del__

我的例子:

class MyClass(object): 

    count = 0 
    #instances = [] 

    def __init__(self, a, b): 
     self.a = a 
     self.b = b 
     MyClass.count += 1 
     #MyClass.instances.append(self) 

    def __str__(self): 
     return self.__repr__() 

    def __repr__(self): 
     return "a: " + str(self.a) + ", b: " + str(self.b) 

    def __del__(self): 
     MyClass.count -= 1 
     #MyClass.instances.remove(self) 

A = MyClass(1,'abc') 
B = MyClass(2,'def') 
print MyClass.count 
del B 
print MyClass.count 

有了意見,我得到正確的答案:

2 
1 

但沒有註釋 - 現在包括靜態對象列表MyClass.instances我得到錯誤的答案:

2 
2 

看起來像MyClass無法達到它的__del__方法a nymore!怎麼來的?

回答

1

從到http://docs.python.org/2.7/reference/datamodel.html#basic-customization我引用(灰色款object.__del__後):

del x不直接調用x.__del__() - 前遞減x的引用計數的一個,而後者只調用當x參考計數達到零。

在這裏,您撥打del B但仍有B的一個實例在MyClass.instances,所以B是仍然被引用,因此不被破壞,從而使__del__函數沒有被調用。 如果你直接打電話B.__del__(),它的工作原理。

3

docs

del x doesn’t directly call x.__del__() — the former decrements the reference 
count for x by one, and the latter is only called when x‘s reference count 
reaches zero. 

當你取消註釋,

instances = [] 
... 
... 
MyClass.instances.append(self) 

你是存儲在MyClass.instances當前對象的引用。這意味着,引用計數在內部增加1.這就是爲什麼__del__沒有立即被調用。

要解決此問題,明確從列表中刪除的項目像這樣

MyClass.instances.remove(B) 
del B 

現在它將打印

2 
1 

預期。

還有一種方法可以解決這個問題。那就是用weakref。從docs

弱引用一個對象是不夠的,以保持物體活着: 時,所指對象僅存的引用是弱引用, 垃圾回收是免費摧毀指涉和重用其 記憶別的東西。弱引用的主要用途是 實現緩存或持有大對象的映射,其中期望 大對象不會因僅出現在 緩存或映射中而保持活動狀態。

因此,擁有weakref不會推遲對象的刪除。隨着weakref,這可以固定這樣

MyClass.instances.append(weakref.ref(self)) 
... 
... 
# MyClass.instances.remove(weakref.ref(self)) 
MyClass.instances = [w_ref for w_ref in MyClass.instances if w_ref() is None] 

而不是使用remove的方法,我們可以調用每個weakref對象,如果他們返回None,他們已經死了。所以,我們用列表理解過濾出來。

所以,現在,當你說del B,即使對於B存在weakref S,它會調用__del__(除非你已經取得了一些其他變量指向同一個對象,就像做一個分配新建分配FY)。

1

__del__僅在沒有更多實例離開時被調用。

您應該考慮在MyClass.instances列表中只放入弱符號。

這可以用import weakref然後

  • 或者使用一個WeakSet爲列表
  • 或將weakref.ref(self)到列表中來實現和。

__del__每當最後一個「嚴格」引用被刪除時自動調用。這些虛假信息會自動消失。

但請注意,docs中提到的__del__有一些注意事項。

0

__del__用於垃圾收集器從內存中移除對象。如果將對象添加到MyClass.instances中,則該對象將被標記爲「已使用」,垃圾收集器將永遠不會嘗試將其移除。所以__del__永遠不會被調用。

您最好使用顯式函數(MyClass.del_element()),因爲您無法真正預測何時調用__del__(即使您未將其添加到列表中)。