首页 > 解决方案 > Python: can view objects show keys of zombie dictionaries?

问题描述

Here is my example code:

#!/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)

If you run the program as shown here (with the line in the middle commented out), you get this output, which is exactly what I expected. The lines with the prefix D (loop over dictionary) have the same values as the lines with the prefix K (loop over keys of dictionary):

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

Now remove the hash and activate the line that was commented out. When you run the modified program, you get this:

D y
K a
K b
K c

But I expected one of these behaviors:

   D y
   K y

But to me is looks as if the old version of myDict has become some kind of zombie, and myKeys is displaying the keys of this zombie.


So, here are my questions:

  1. Is it true, that in my program myKeys shows keys of a zombie dictionary if the line in the middle is activated?
  2. Is it reliable behavior, that myKeys will always show the keys of the previous version of the dictionary? (That would be very helpful for a program that I'm writing just now.)
  3. Is there a way to revive the zombie dictionary? (I have all keys. Can I get the values too?)

标签: pythonpython-3.xdictionary

解决方案


The fundamental issue in your understanding here is that:

myDict = {}

Does nothing to the original dict, assignment never mutates, so the object that myDict was referring to is unmodified. Python objects will stay alive as long as something refers to them. CPython uses reference counting, and as an implementation detail, will reclaim objects immediately when their reference count reaches zero.

However, the dict_keys view object you created internally references the dictionary it is acting as a view over, so the original dictionary still has at least one reference to it, since the view object is alive. Note, though, the dict_keys API does not expose this reference, so if it is the only reference, you cannot really access your dict anymore (in any sane way).

Is it reliable behavior, that myKeys will always show the keys of the previous version of the dictionary?

You are misunderstanding the behavior. It is showing the keys of the same dictionary it has always been showing. There is no previous dictionary. The view is over the object, it doesn't care or know which variables happen to be referring to that object at any given time.

It's the same reason that if you do:

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

will still print "foo". Objects have no idea what names are referencing them at any given time, and should not care. And when one reference changes, the other references don't magically get updated.


推荐阅读