在python 3.7上,我希望每次调用iterator.cycle时都会获得一个新的内存地址(和周期),但是,这段代码在4上复制了2个迭代器:
false
它打印:
from itertools import cycle
cycles = [[None] * 2] * 2
s = set()
for i in range(2):
for j in range(2):
c = cycle("ab")
cycles[i][j] =c
s.add(hex(id(c)))
print(hex(id(c)))
print(len(s))
因此对象0x7efe576cc370
0x7efe576cc3c0
0x7efe576cc410
0x7efe576cc370
3
被使用了两次。另一方面,此代码有效:
0x7efe576cc370
答案 0 :(得分:1)
这里的问题是构造cycles
对象的方式。
在列表上使用*
运算符时,返回的新列表包含对原始列表的多个引用,而不是原始列表的副本。
因此,cycles
是一个两个项目的列表,两个元素都指向同一列表,因此对cycles[1][0]
所做的更改也适用于cycles[0][0]
分配给cycles[1][0]
时,您还将覆盖cycles[0][0]
上的项目,这会删除上一个项目。
为什么这意味着s
的长度为3,这是由于对象分配器/垃圾收集器交互的方式。
对于除了最里面的列表以外的任何东西,都应该使用列表理解来构造对象。
cycles = [[None] * 2 for _ in range(2)]
这将产生一个适当构建的列表,并且您的代码可以正常工作
答案 1 :(得分:0)
每次迭代都会创建一个新对象,但是id函数的文档显示以下内容:
返回对象的“身份”。这是一个整数 保证在此对象期间它是唯一且恒定的 一生。 两个具有非重叠生命周期的对象可能具有 相同的id()值。
CPython实现细节:这是对象的地址 记忆。
您在第二个示例中证明了该语句,在该示例中,您保留了所有对象,以便它们的寿命重叠。
示例1(x2个唯一ID):
return cost
示例2(5个唯一ID):
>>> from itertools import cycle
>>> for i in range(5):
... c = cycle('ab')
... print(hex(id(c)))
...
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140