Jim*_*ard 5 python dictionary python-3.x
因为dict.keys(和dict.items和dict.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)
有谁知道为什么会这样?
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)
调用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)将原始字典的引用计数再次增加一,使对象远离集合。