我删除了我的字典,但我的dict_keys不介意,为什么呢?

Jim*_*ard 5 python dictionary python-3.x

因为dict.keys(和dict.itemsdict.values一样)返回字典对象的看法,我会认为他们删除从实际制作的字典对一个影响dict_keys我们从得到了他们.

使用简单的字典及其键:

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

显然,事实并非如此:

del d
i = iter(k)
list(i) # works fine and prints the keys
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么会这样?

zwo*_*wol 9

del d删除变量 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'}
Run Code Online (Sandbox Code Playgroud)

(该d['x']='x'线表明,dd=d复制词典本身,它才有附加的参考.)

还对比了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)
[]
Run Code Online (Sandbox Code Playgroud)


Jim*_*ard 4

调用d.keys()该对象只会增加字典对象的引用计数;del d不会触发由名称标记的对象的垃圾收集器,d因为引用始终大于零。

d.keys()您可以看到使用以下命令调用时字典对象的引用计数增加sys.getrefcount

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())
Run Code Online (Sandbox Code Playgroud)

在构造字典视图的调用中可以看到这个引用增量

Py_INCREF(dict);
dv->dv_dict = (PyDictObject *)dict;
Run Code Online (Sandbox Code Playgroud)

它是在对象存储在视图对象结构的相应条目之前完成的。

由于视图实际上只是一个可迭代对象,带有对底层字典的引用,因此您还可以更进一步,在获取其迭代器后删除键对象,并且仍然能够获取值:

i = iter(k) # +1 reference
del k, d
next(i)     # 0
Run Code Online (Sandbox Code Playgroud)

iter(k)将原始字典的引用计数再次增加一,使对象远离集合。