3

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

这段代码

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

1 回答 1

3

好的!在对原文的评论中,我们确定了

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 才知道它拥有对所产生对象的唯一引用,因此它是安全的变异它。但是如果 refcount 大于 1,CPython 会创建一个新对象来 yield(因为用户可能会保留最后一个 yield - 正如 @eeeeeeeeee 在他的示例代码中所做的那样)。

我会向包作者抱怨这种行为。它充其量是令人困惑和容易出错的:-(

于 2013-09-17T23:31:32.200 回答