iterator.cycle 函数调用两次 return 同一个迭代器(具有相同的内存地址)
iterator.cycle function called twice return the same iterator (with same memory adress)
在python 3.7上,我希望每次调用iterator.cycle时都能得到一个新的内存地址(和循环),然而,这段代码在4:[=16上复制了2个迭代器=]
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
被使用了两次。另一方面,此代码有效:
from itertools import cycle
cycles = []
for _ in range(1000):
c = cycle("ab")
cycles.append(c)
s = set([hex(id(c)) for c in cycles])
print(len(s)) # 1000
每次迭代都会创建一个新对象,但是 id 函数的文档说明如下:
Return the “identity” of an object. This is an integer which is
guaranteed to be unique and constant for this object during its
lifetime. Two objects with non-overlapping lifetimes may have the
same id() value.
CPython implementation detail: This is the address of the object in
memory.
您在第二个示例中证明了这一说法,您保留所有对象以便它们的生命周期重叠。
示例 1(x2 个唯一 ID):
>>> from itertools import cycle
>>> for i in range(5):
... c = cycle('ab')
... print(hex(id(c)))
...
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140
示例 2(x5 个唯一 ID):
>>> store = []
>>> for i in range(5):
... c = cycle('ab')
... store.append(c)
... print(hex(id(c)))
...
0x7fdac5e20680
0x7fdac5d17340
0x7fdac5d17300
0x7fdac5d172c0
0x7fdac5d17240
这里的问题是您构建 cycles
对象的方式。
当您在列表上使用 *
运算符时,返回的新列表包含对原始列表的多个引用,而不是原始列表的副本。
因此,cycles
是一个包含两项的列表,其中两个元素指向同一个列表,因此对 cycles[1][0]
所做的更改也适用于 cycles[0][0]
当您分配给 cycles[1][0]
时,您还覆盖了 cycles[0][0]
处的项目,这会删除之前的项目。
至于为什么这意味着 s
的长度为 3,这是由于对象分配器/垃圾收集器交互的方式。
除了最里面的列表,您应该使用列表理解来构造对象。
cycles = [[None] * 2 for _ in range(2)]
这将生成一个适当构建的列表,您的代码将正常工作
在python 3.7上,我希望每次调用iterator.cycle时都能得到一个新的内存地址(和循环),然而,这段代码在4:[=16上复制了2个迭代器=]
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
被使用了两次。另一方面,此代码有效:
from itertools import cycle
cycles = []
for _ in range(1000):
c = cycle("ab")
cycles.append(c)
s = set([hex(id(c)) for c in cycles])
print(len(s)) # 1000
每次迭代都会创建一个新对象,但是 id 函数的文档说明如下:
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.
您在第二个示例中证明了这一说法,您保留所有对象以便它们的生命周期重叠。
示例 1(x2 个唯一 ID):
>>> from itertools import cycle
>>> for i in range(5):
... c = cycle('ab')
... print(hex(id(c)))
...
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140
0x7fdac5d54180
0x7fdac5d54140
示例 2(x5 个唯一 ID):
>>> store = []
>>> for i in range(5):
... c = cycle('ab')
... store.append(c)
... print(hex(id(c)))
...
0x7fdac5e20680
0x7fdac5d17340
0x7fdac5d17300
0x7fdac5d172c0
0x7fdac5d17240
这里的问题是您构建 cycles
对象的方式。
当您在列表上使用 *
运算符时,返回的新列表包含对原始列表的多个引用,而不是原始列表的副本。
因此,cycles
是一个包含两项的列表,其中两个元素指向同一个列表,因此对 cycles[1][0]
所做的更改也适用于 cycles[0][0]
当您分配给 cycles[1][0]
时,您还覆盖了 cycles[0][0]
处的项目,这会删除之前的项目。
至于为什么这意味着 s
的长度为 3,这是由于对象分配器/垃圾收集器交互的方式。
除了最里面的列表,您应该使用列表理解来构造对象。
cycles = [[None] * 2 for _ in range(2)]
这将生成一个适当构建的列表,您的代码将正常工作