2012-09-14 36 views
5

安全迭代的的Python 3.2的文檔weakref模塊的WeakKeyDictionaryWeakValueDictionary對遍歷這些集裝箱一注:超過WeakKeyDictionary和WeakValueDictionary

注:注意:由於WeakKeyDictionary是建立在在Python字典的頂部,它在迭代時不能改變大小。這可能難以確保WeakKeyDictionary,因爲程序在迭代過程中執行的操作可能會導致字典中的項目「通過魔術」消失(作爲垃圾回收的副作用)。

作爲這些容器行爲的規範,這似乎相當可怕。特別是在運行使用CPython的垃圾收集器(使用包含循環的數據結構時)或使用其他Python實現(例如Jython)的代碼時,聽起來好像沒有安全的方式來遍歷這些集合。

當垃圾收集器可以在我的程序中的任何位置清除引用時,如何安全地遍歷這些集合?有一個CPython的解決方案是我的首要任務,但我也對其他實現方面的問題感興趣。

這可能是一個安全的方式來遍歷WeakKeyDictionary?

import weakref 

d = weakref.WeakKeyDictionary() 

... 

for k, v in list(d.items()): 
    ... 

回答

6

爲了安全起見,您必須在某處保留參考。使用成語:

for k,v in list(d.items()): 

不是完全安全的,因爲,即使它會工作的大部分時間,循環列表可能是垃圾收集的最後一次迭代中。

正確的方法是:

items = list(d.items()) 
for k,v in items: 
    #do stuff that doesn't have a chance of destroying "items" 
del items 

如果使用WeakKeyDictionary你可以簡單地存儲密鑰,並存儲值如果使用WeakValueDictionary

附註:python2 .items()已經返回一個列表。

最終它取決於你的意思是「安全」。如果你僅僅意味着迭代將會正確地進行(上的所有元素迭代一次),然後:

for k,v in list(d.items()): 

是安全的,因爲在字典中的迭代實際上是由list(d.items())執行,那麼你只遍歷名單。

如果你的意思是在迭代期間元素不應該從字典中「消失」作爲for -loop的副作用,那麼你必須保持強引用直到循環結束,這就需要您在開始循環之前將列表存儲在變量中。

+2

爲什麼你的第一個例子不安全?該列表將包含對每個鍵和值的強引用,並且在最後一次迭代期間,'k'和'​​v'擁有對我感興趣的對象的強引用。因此,即使在最後一次迭代終止之前,列表也可能被垃圾收集。是對的嗎? – Feuermurmel

+0

這就好像在說'for k,v in d.items()'是安全的,因爲'k'和'​​v'擁有對象的強引用。迭代是不安全的,如果在for循環中有'k'和'​​v'被刪除的機會。對於遍歷'WeakKeyDictionary'的簡單任務應該是安全的。 – Bakuriu

+3

我可能誤解了一些東西,但是如何刪除對象'k'和'​​v'引用?只要這些變量在範圍內而不是超範圍,那麼所引用的對象就是安全的。或者你是否在談論在上一次迭代期間刪除對這些對象的所有強引用?這將改變字典,但不會因爲字典在迭代開始後不被訪問而變得不安全。你能舉一個例子說明在最後一次迭代中可能出錯嗎? – Feuermurmel