为什么这些对象(来自生成器)在我将它们添加到列表时会发生变化?

时间:2013-09-17 23:06:24

标签: python

所以我试图从生成器中获取对象并将它们添加到列表中。但是当我将它们添加到列表中时,列表会填充空对象而不是我添加的对象。那是为什么?

此代码

#!/usr/bin/python

# Create a graph with 5 nodes
from snap import *

G = TUNGraph.New()

for i in range(5):
    G.AddNode(i)

# Ids of these nodes are 0, 1, 2, 3, 4
for node in G.Nodes():  # G.Nodes() is a generator
    print node.GetId()

lst = []
for node in G.Nodes():
    lst.append(node)

print
# All of the nodes magically change to have ID -1
print [node.GetId() for node in lst]

print
# The nodes in the original graph are unchanged
for i in G.Nodes():
    print i.GetId()

产生输出

0
1
2
3
4

[-1, -1, -1, -1, -1]

0
1
2
3
4

1 个答案:

答案 0 :(得分:3)

OK!在对原文的评论中,我们建立了

for node in G.Nodes():  # G.Nodes() is a generator
    print node.GetId()
    print id(node)  #  NEW LINE HERE

每次为id(node)打印相同的内容。

这意味着生成器每次都返回相同的对象,并在调用之间进行变异。列表中的“对象”都是相同的对象,其状态反映了Nodes()实现在内的所有内部工作。

我认为这是糟糕的设计,虽然我没有使用过SNAP,所以无法确定。这是我经常看到的微效率技巧。当CPython在内部执行类似这样的操作时,它首先检查所产生的对象上的引用计数是否为1.当且仅当它为1时,CPython知道它包含 only 对所产生的引用的引用对象,所以改变它是安全的。但是如果refcount大于1,CPython会创建一个新的对象来生成(因为用户可能会保留最后一个产生的对象 - 正如@eeeeeeeeee在他的示例代码中所做的那样)。

我向包裹作者抱怨这种行为。这最多令人困惑且容易出错: - (