调用两次的iterator.cycle函数返回相同的迭代器(具有相同的内存地址)

时间:2020-05-23 21:56:26

标签: python memory-address cycle

在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

2 个答案:

答案 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