代码之家  ›  专栏  ›  技术社区  ›  Ani Menon

python中的浅拷贝

  •  3
  • Ani Menon  · 技术社区  · 6 年前

    我有点搞不懂浅拷贝是怎么工作的,我的理解是我们什么时候做的 new_obj = copy.copy(mutable_obj)

    我困惑的例子-

    ## assignment
    i = [1, 2, 3]
    j = i
    id(i[0]) == id (j[0])  # True
    i[0] = 10
    i  # [10, 2, 3]
    j  # [10, 2, 3]
    
    ## shallow copy
    k = copy.copy(i)
    k   # [10, 2, 3]
    id(i) == id(k)  # False (as these are two separate objects)
    id(i[0]) == id (k[0])  # True (as the reference the same location, right?)
    i[0] = 100
    id(i[0]) == id (k[0])  # False (why did that value in that loc change?)
    id(i[:]) == id (k[:])  # True  (why is this still true if an element just changed?)
    i   # [100, 2, 3]
    k   # [10, 2, 3]
    

    k[0] 只是指着 i[0] 类似于任务?不应该 k[0] 更改时间 我[0] 变化?

    i = [1, 2, [3]]
    k = copy(i)
    i  # [1, 2, [3]]
    k  # [1, 2, [3]]
    i[2].append(4)
    i  # [1, 2, [3, 4]]
    k  # [1, 2, [3, 4]]
    id(i[0]) == id (k[0])  # True
    id(i[2]) == id (k[2])  # True
    id(i[:]) == id (k[:])  # True
    
    3 回复  |  直到 6 年前
        1
  •  3
  •   Community paulsm4    4 年前

    id(i) == id(k) # False (as these are two separate objects)

    对的。

    id(i[0]) == id (k[0]) # True (as the reference the same location, right?)

    对的。

    i[0] = 100

    id(i[0]) == id (k[0]) # False (why did that value in that loc change?)

    它变了,因为 . i[0] 磨尖 10 ,但您将其改为指向 100 . 因此, k[0] 现在不再指向同一个点。

    单向 . 10 不知道是什么指向它。我也不知道 . 它们只是记忆中的位置。所以如果你改变了 哪里 i k 不在乎(因为 k 相同的参考)。 k 的第一个元素仍然指向它一直指向的对象。

    id(i[:]) == id (k[:]) # True (why is this still true if an element just changed?)

    这个有点微妙,但请注意:

    >>> id([1,2,3,4,5]) == id([1,2,3])
    True
    

    鉴于

    >>> x = [1,2,3,4,5]
    >>> y = [1,2,3]
    >>> id(x) == id(y)
    False
    

    这与垃圾收集和id的一些微妙之处有关,这里有深入的回答: Unnamed Python objects have the same id .

    id([1,2,3,4,5]) == id([1,2,3]) [1,2,3,4,5] id [1,2,3,4,5] 立即 收回它。然后,我们创建另一个匿名对象, [1,2,3] [1,2,3] 也会立即被删除和清理。但是,如果您存储引用,GC就不会妨碍您,那么引用就不同了。

    可变项示例

    如果重新分配可变对象,也会发生同样的情况。举个例子:

    >>> import copy
    >>> a = [ [1,2,3], [4,5,6], [7,8,9] ]
    >>> b = copy.copy(a)
    >>> a[0].append(123)
    >>> b[0]
    [1, 2, 3, 123]
    >>> a
    [[1, 2, 3, 123], [4, 5, 6], [7, 8, 9]]
    >>> b
    [[1, 2, 3, 123], [4, 5, 6], [7, 8, 9]]
    >>> a[0] = [123]
    >>> b[0]
    [1, 2, 3, 123]
    >>> a
    [[123], [4, 5, 6], [7, 8, 9]]
    >>> b
    [[1, 2, 3, 123], [4, 5, 6], [7, 8, 9]]
    

    不同的是当你说 a[0].append(123) ,我们正在修改任何东西 a[0] b[0] 指向同一个对象( a[0] b[0] 是指

    a[0] 新的 对象(通过赋值,如 a[0] = [123] b[0]

        2
  •  2
  •   StuxCrystal    6 年前

    在Python中,所有的东西都是对象。这包括整数。所有列表仅包含对对象的引用。替换列表中的某个元素并不意味着该元素本身会发生更改。

    考虑另一个例子:

    class MyInt:
        def __init__(self, v):
            self.v = v
        def __repr__(self):
            return str(self.v)
    
    >>> i = [MyInt(1), MyInt(2), MyInt(3)]
    [1, 2, 3]
    >>> j = i[:] # This achieves the same as copy.copy(i)
    
    [1, 2, 3]
    >>> j[0].v = 7
    >>> j
    [7, 2, 3]
    >>> i
    [7, 2, 3]
    
    >>> i[0] = MyInt(1)
    >>> i
    [1, 2, 3]
    >>> j
    [7, 2, 3]
    

    整数也是如此。你不能修改它们。

        3
  •  0
  •   shirish    6 年前
    • 在第一种情况下 j = i 是赋值,j和i都指向同一个list对象。
    • 在第二种情况下 k = copy.copy(i)
      浅层副本不会创建嵌套对象的副本,而只是复制嵌套对象的引用。请参考这个 https://www.programiz.com/python-programming/shallow-deep-copy
    • 因此i和k有不同的引用集指向相同的不可变对象。当你这么做的时候 i[0] = 100 ,列表i中的引用指向值为100的新int对象,但k中的引用仍然引用值为10的旧int对象。