【问题标题】:iterator.cycle function called twice return the same iterator (with same memory adress)调用两次的 iterator.cycle 函数返回相同的迭代器(具有相同的内存地址)
【发布时间】:2020-05-23 21:56:26
【问题描述】:

在 python 3.7 上,我希望每次调用 iterator.cycle 时都会获得一个新的内存地址(和循环),但是,这段代码在 4 上复制了 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

【问题讨论】:

    标签: python memory-address cycle


    【解决方案1】:

    这里的问题是您构造 cycles 对象的方式。

    当您对列表使用* 运算符时,返回的新列表包含对原始列表的多个引用,而不是原始列表的副本。

    因此,cycles 是一个包含两个元素的列表,其中两个元素都指向同一个列表,因此对 cycles[1][0] 所做的更改也适用于 cycles[0][0]

    当您分配给cycles[1][0] 时,您还会覆盖cycles[0][0] 处的项目,这会删除前一个项目。

    至于为什么这意味着s 的长度为3,这是由于对象分配器/垃圾收集器交互的方式。

    除了最里面的列表之外,您应该使用列表推导来构造对象。

     cycles = [[None] * 2 for _ in range(2)] 
    

    这将生成一个适当构造的列表,并且您的代码可以正常工作

    【讨论】:

    • 这其实很有道理,这是我第一次将 * 用于嵌套列表。我不知道 * 运算符重复引用对象而不是复制对象本身,谢谢!
    【解决方案2】:

    每次迭代都会创建一个新对象,但 id 函数的文档说明如下:

    返回对象的“身份”。这是一个整数,它是 保证在此对象期间是唯一且恒定的 寿命。 两个生命周期不重叠的对象可能有 相同的 id() 值。

    CPython implementation detail: 这是对象的地址 记忆。

    您在第二个示例中证明了这一陈述,您保留所有对象以使其生命周期重叠。

    示例 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
    

    【讨论】:

      猜你喜欢
      • 2014-10-12
      • 2021-05-26
      • 1970-01-01
      • 2018-08-27
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      相关资源
      最近更新 更多