2017-02-10 13 views
5

由於dict.keys(和dict.itemsdict.values相同)返回字典對象的視圖,我會假設刪除它們生成的字典實際上對我們從dict_keys產生的影響。我刪除了我的字典,但我的dict_keys不介意,爲什麼?

用一個簡單的字典,它的鍵:

d = {i:i for i in range(20)} 
k = d.keys() # similarly with d.values and d.items 

顯然,這是不是這樣的:

del d 
i = iter(k) 
list(i) # works fine and prints the keys 

有誰知道爲什麼是這樣的話?

回答

4

在對象上調用d.keys()只是增加字典對象的引用計數; del d將不會觸發由名稱d標記的對象的垃圾收集器,因爲引用將始終大於零。

你可以看到Dictionary對象增加引用計數時d.keys()通過使用sys.getrefcount稱爲:

Py_INCREF(dict); 
dv->dv_dict = (PyDictObject *)dict; 

它的完成:

from sys import getrefcount 
d = {i:i for i in range(20)} 
getrefcount(d) # 2 
k = d.keys() 
getrefcount(d) # 3 (+1 due to d.keys()) 
在構建這個 reference increment can be seen字典視圖通話

就在對象被存儲在視圖對象結構的對應條目之前。

由於視圖實際上只是通過對底層字典引用一個迭代的對象,你也可以走一步深入和刪除獲取其迭代後的按鍵對象,仍然有獲得值的能力:

i = iter(k) # +1 reference 
del k, d 
next(i)  # 0 

iter(k) increases the reference count原始字典由一個再次,保持對象遠離收集。

+0

是@AlexFung,當你能夠正確地做到這一點(我盡我所能,做),這是允許的。看到這裏[我可以回答我自己的問題嗎?](http://stackoverflow.com/help/self-answer) –

+0

@ JimFasarakis-Hilliard酷。我不知道立即自我回答是鼓勵 –

9

del d刪除變量d,但對象,它是指將繼續,如果有其他的引用存在。你並不需要一個字典視圖來觀察這樣的:(該d['x']='x'線表明dd=d複製字典本身,它纔有額外的參考)

>>> d = {i:i for i in range(5)} 
>>> dd = d 
>>> d['x'] = 'x' 
>>> del d 
>>> d 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'd' is not defined 
>>> dd 
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 'x': 'x'} 

而且對比的clear行爲,修改了實際的對象:

>>> d = {i:i for i in range(5)} 
>>> k = d.keys() 
>>> del d 
>>> list(k) 
[0, 1, 2, 3, 4] 

>>> d = {i:i for i in range(5)} 
>>> k = d.keys() 
>>> d.clear() 
>>> list(k) 
[] 
相關問題