2017-05-10 88 views
0

我不確定python如何處理循環引用(引用循環)。我檢查一些答案,發現thispython中的循環引用

Python的標準引用計數機制不能釋放週期,所以你的例子中的結構會泄漏。
但是,補充垃圾回收工具默認情況下處於啓用狀態,並且應該可以釋放該結構,如果其組件都不再可從外部訪問且它們沒有__del__()方法。

我想這意味着如果參考循環中沒有實例可以到達外部,它們都將被清除。這是真的?
另一方面,,有一個包weakref這是經常用來處理地圖字典。我想,其存在的目的是避免參考循環。
綜上所述,python可以自動處理參考週期嗎?如果可以,爲什麼我們必須使用weakref

回答

2

如果循環中的對象沒有自定義的__del__方法,則不必擔心引用週期,因爲Python可以(也將)以任何順序銷燬對象。

如果你的自定義方法確實有一個__del__方法,Python不知道是否有一個對象的刪除會影響另一個對象的刪除。說一個對象被刪除時,它會設置一些全局變量。所以,這些物體粘在一起。作爲一個快速測試,你可以做一個__del__方法,打印的東西:

class Deletor(str): 
    def __del__(self): 
     print(self, 'has been deleted') 

a = Deletor('a') # refcount: 1 
del a    # refcount: 0 

輸出:

a has been deleted 

但是,如果你有這樣的代碼:

a = Deletor('a') # refcount: 1 
a.circular = a # refcount: 2 
del a    # refcount: 1 

它什麼也不輸出,因爲Python不能安全地刪除a

有兩種解決方案。該weakref

# refcount:    a b 
a = Deletor('a')  # 1 0 
b = Deletor('b')  # 1 1 
b.a = a    # 2 1 
a.b = weakref.ref(b) # 2 1 
del a     # 1 1 
del b     # 1 0 
# del b kills b.a  # 0 0 

輸出:

b has been deleted 
a has been deleted 

(注意:第一是如何b刪除,它可以刪除a前)

你也可以手動刪除週期(如果你可以跟蹤他們):

# refcount   a b 
a = Deletor('a') # 1 0 
b = Deletor('b') # 1 1 
b.a = a   # 2 1 
a.b = b   # 2 2 
del b    # 2 1 
print('del b') 
del a.b   # 2 0 
# b is deleted, now dead 
# b.a now dead # 1 0 
print('del a.b') 
del a    # 0 0 
print('del a') 

輸出S:

del b 
b has been deleted 
del a.b 
a has been deleted 
del a 

注意b如何後a.b刪除被刪除。

2

試圖回答爲什麼我們然後有弱引用子問題。

Weakrefs不僅可以打破循環引用,還可以防止不需要的非循環引用。

我最喜歡的例子是使用WeakSet來計算同時網絡連接(負載測量的種類)。在這個例子中,每個新的連接必須被添加到WeakSet,但這是網絡代碼需要完成的唯一任務。連接可以由服務器,客戶端或錯誤處理程序關閉,但這些例程都沒有責任從集中刪除連接,這是因爲其他引用很弱。