Python:视图对象可以显示僵尸字典的键吗



下面是我的示例代码:

#!/usr/bin/env python3
myDict = {'a':1, 'b':2, 'c':3}
myKeys = myDict.keys()
# myDict = {} # toggle this line
myDict['y'] = 4
for myKey in myDict:
print('D ' + myKey)
for myKey in myKeys:
print('K ' + myKey)

如果你运行这里显示的程序(中间的一行注释掉了(,你会得到这个输出,这正是我所期望的。前缀为D(字典上的循环(的行与前缀为K(字典的键上的循环(loop-over keys((的行具有相同的值:

D a
D b
D c
D y
K a
K b
K c
K y

现在删除散列并激活被注释掉的行。当你运行修改后的程序时,你会得到这个:

D y
K a
K b
K c

但我预料到了其中一种行为:

  • 任一:在执行myDict = {}之后,myKeys也变为空(因为它是一个始终查看其父字典键的视图对象(。添加具有关键字'y'的项应得到以下输出:
D y
K y
  • 或:在执行myDict = {}之后,创建了新版本的myDict,并销毁了以前版本的myDict,因此myKeys不再有任何父字典,因此指向null。因此,在这种情况下,在myKeys上循环应该会引发一个错误

但对我来说,旧版本的myDict似乎变成了某种僵尸,而myKeys正在显示这个僵尸的密钥。


所以,以下是我的问题:

  1. 在我的程序中,如果中间的行被激活,myKeys会显示僵尸字典的键,这是真的吗
  2. myKeys总是显示以前版本的字典的键,这是可靠的行为吗?(这对我现在正在写的一个程序非常有帮助。(
  3. 有没有办法让僵尸字典复活?(我有所有的键。我也能得到值吗?(

您理解这里的基本问题是:

myDict = {}

对原始dict不执行任何操作赋值从不发生变化。因此myDict所指的对象未修改。只要有东西引用了Python对象,它们就会一直存在。CPython使用引用计数,并且作为实现细节,当对象的引用计数达到零时,将立即收回对象

但是,您创建的dict_keys视图对象在内部引用它作为视图的字典,因此原始字典仍然至少有一个引用,因为视图对象是活动的。但是,请注意,dict_keysneneneba API并没有公开这个引用,所以如果它是唯一的引用,那么您就不能再真正访问您的dict了(以任何合理的方式(。

myKeys总是显示以前版本字典的密钥,这是可靠的行为吗?

你误解了这种行为。它显示的是它一直显示的同一本词典的关键字。没有以前的字典。视图位于对象之上,它不关心或不知道在任何给定时间哪些变量碰巧引用了该对象。

这与如果你这样做的原因相同:

x = 'foo'
container = []
container.append(x)
x = 'bar'
print(container[0])

仍将打印"foo"。对象不知道在任何给定时间引用它们的名称是什么,也不应该在意。当一个引用发生变化时,其他引用不会神奇地更新。

最新更新