【问题标题】:How does `is` work in the case of ephemeral objects sharing the same memory address? [duplicate]在临时对象共享相同内存地址的情况下,“is”如何工作? [复制]
【发布时间】:2019-06-17 08:12:59
【问题描述】:

请注意,这个问题可能(是?)特定于 CPython。

假设您有一些清单,并检查清单的副本以确认彼此的身份:

>>> a=list(range(10))
>>> b,c=a[:],a[:]
>>> b is c
False
>>> id(b), id(c)
(3157888272304, 3157888272256)

那里没有很大的震动。但如果我们以更短暂的方式执行此操作,一开始事情可能看起来有点奇怪:

>>> a[:] is a[:]
False  # <- two ephemeral copies not the same object (duh)
>>> id(a[:]),id(a[:])
(3157888272544, 3157888272544)   # <- but two other ephemerals share the same id..? hmm....

...直到我们认识到这里可能发生了什么。我没有通过查看 CPython 实现来确认这一点(我几乎看不懂 c++,所以说实话,这将是浪费时间),但至少看起来很明显,即使两个对象具有相同的 id,CPython 也很聪明足以知道它们不是同一个对象。

假设这是正确的,我的问题是:CPython 使用什么标准来确定这两个临时对象是否不是同一个对象,因为它们具有相同的 id(可能是出于效率原因 - 见下文)?它是否可能正在查看它被标记为垃圾收集的时间?创建时间?还是别的什么...?

我关于为什么他们具有相同 id 的理论是,很可能,CPython 知道列表的临时副本已经制作并等待被垃圾收集,它只是有效地重用相同的内存位置。如果答案也能澄清/确认这一点,那就太好了。

【问题讨论】:

  • 你不能比较两个恰好具有相同 id 的不同的短暂对象 - 你正在比较它们的事实意味着它们同时存在,这意味着没有机会第二个对象分配在与第一个对象相同的地址。
  • 您创建的要传递给id 的list 对象在传递给id 后不再存在。请记住,CPython 引用计数只要引用计数变为零,就会回收一个对象。 CPython 运行时有一个私有管理的堆,它非常适合重用内存。 Python 继续并重新使用相同的内存来分配您的新列表对象,并传递给id 的第二次调用。所以,换句话说,这两个对象没有重叠的生命周期,因此,id 不能保证是唯一的
  • 在a[:] is a[:]中,两边的id不一样。
  • 我仍然认为它是一个有效的副本,因为您根本误解了对象在其生命周期内共享相同的 id。但请随意投票以重新开放。
  • 仅仅因为某些东西是重复的并不意味着它是一个坏问题。这个不时以各种形式出现。我添加了一些其他更密切相关的重复目标

标签: python python-3.x cpython


【解决方案1】:

两个不可变的对象,共享相同的地址,在您看来,彼此无法区分。

问题是,当您执行 a[:] is a[:] 时,两个对象 not 在同一地址 - 为了让身份运算符 is 比较两个对象,两个操作数都必须存在 - 所以,当 is 的本机代码实际运行时,仍然存在对左侧对象的引用。

另一方面,当您执行id(a[:]),id(a[:]) 时,第一次调用时括号内的对象在id 函数调用完成后立即没有任何引用,并被销毁,释放内存块被第二个a[:]使用。

【讨论】:

    猜你喜欢
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    相关资源
    最近更新 更多