【问题标题】:If the elements of the list point to same memory address, how are the two list not referring to the same object?如果列表的元素指向相同的内存地址,那么两个列表如何不引用同一个对象?
【发布时间】:2021-01-13 12:19:38
【问题描述】:

我初始化两个列表如下:

>>> a = [1]
>>> b = [1]

然后我在两个列表的索引 0 处找到元素的内存位置:

>>> id(a[0])
93961440619840
>>> id(b[0])
93961440619840

两个元素的地址相同。但是当我试图找出两个列表是否引用同一个对象时,我得到'False'

>>> a is b
False

我的问题是,如果列表的元素引用了同一个内存,为什么列表不引用同一个对象?

【问题讨论】:

    标签: python list data-structures


    【解决方案1】:

    我的问题是,如果列表的元素引用了同一个内存,为什么列表不引用同一个对象?

    因为列表是可变对象,所以每个列表字面量必须创建一个独立于前一个列表对象的全新列表对象^[0]。否则

    >>> a = []
    >>> b = []
    >>> a.append(1)
    >>> print(b)
    

    将打印 [1] 而不是空列表,这太疯狂了。

    id(a[0])id(b[0]) 尽管是不同的字面值却是相同的原因是 Python 可以预分配/实习生经常使用 不可变 对象以降低内存消耗。

    这是一个实现细节,不能依赖它,因为它是特定实现的内部属性并且它可以随时更改。目前,CPython 将预分配 -5 到 256(包括在内)之间的所有整数,因此即使您通过独立的文字或通过计算创建它们,它们也始终是相同的对象。

    [0] 从技术上讲,cpython(同样是特定实现的内部细节)维护 freelists 对象,因此当“收集”一个列表时,它实际上会被存储起来,以便下次我们可以重用分配需要一份清单,而不必重新分配和设置一个全新的清单。这意味着连续(但不是同时)使用的不同列表可以具有相同的id,即使同时有很多其他分配。

    【讨论】:

    • 在你的例子中,如果'a'和'b'在初始化时是同一个对象,因为它们的元素没有(或相同),但是当你将 1 附加到 'a',然后 'a' 和 'b' 成为不同的对象。
    • 这可能是一种幕后策略但它是不可观察的:在cpython中id实际上是对象在内存中的位置,就地修改对象不能改变这个信息,它不能“返回”并去更新所有指针的指针。所以实现这一点的方法需要你有不同的id,只是两者都是相同底层事物的薄外观,然后在需要时将自己更新为其他东西。
    【解决方案2】:

    只有索引 0 处的元素的内存位置相等,而不是整个列表的内存地址。

    a[0] is b[0] # This returns True
    

    整个列表的内存位置不同:你可以通过输入来测试

    id(a)
    id(b)
    

    Python 这样做是为了减少内存使用

    【讨论】:

      【解决方案3】:

      如果您检查a[0] is b[0],那么它将是True。由于a[0]b[0] 的元素相同,这就是为什么这些ID 也相同。结果是True

      a = [1]
      b = [1]
      print(a[0] is b[0])
      print(id(a[0]), id(a[0]))
      
      # Output
      # True
      # 1793259440 1793259440
      

      现在为什么a is b 是假的?因为 a 和 b 是不同的列表并且具有不同的 id

      print(a is b)
      print(id(a), id(b))
      
      # Output
      # False
      # 9997064 9997800
      

      【讨论】:

        【解决方案4】:

        ab是不同的对象,所以id(a)不等于id(b)

        但是a[0]常量1,等于b[0],并且它们的地址相同,以节省内存。

        帮帮忙。

        【讨论】:

        • 很明显 'a' 和 'b' 是不同的,问题更多的是为什么它们不同,即使它的元素属于相同的内存地址
        • "a" 和 "b" 是不同的列表对象,你可以在其中添加相同的元素,但它们是两个不同的容器。甚至两个空列表对象也是不同的,而你可以说它们都没有元素。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多