Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中的浅拷贝_Python_List_Shallow Copy_Copy Assignment - Fatal编程技术网

python中的浅拷贝

python中的浅拷贝,python,list,shallow-copy,copy-assignment,Python,List,Shallow Copy,Copy Assignment,我对浅层复制的工作原理有点困惑,我的理解是当我们进行new\u obj=copy.copy(mutable\u 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] i

我对浅层复制的工作原理有点困惑,我的理解是当我们进行
new\u obj=copy.copy(mutable\u 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]
类似于赋值?当
i[0]
改变时,
k[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

在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]
我在这里创建了一个类MyInt,它只包含一个int。 通过修改类的实例,这两个类都列出了“更改”。但是,当我替换列表条目时,列表现在不同了

整数也是如此。您无法修改它们。

  • 在第一种情况下,
    j=i
    是一个赋值,j和i都指向同一个列表对象。
    当您更改列表对象的元素并打印i和j时,因为i和j都指向同一个列表对象,并且是元素而不是列表对象发生了更改,所以两者都将打印相同的输出
  • 在第二种情况下,
    k=copy.copy(i)
    是一种浅层复制,其中创建列表对象的副本和嵌套引用的副本,但不复制内部不可变对象。
    浅复制不会创建嵌套对象的副本,而只是复制嵌套对象的引用。请参阅此
  • 因此,i和k具有指向相同不可变对象的不同引用集。当您执行
    i[0]=100
    时,列表i中的引用指向值为100的新int对象,但k中的引用仍然引用值为10的旧int对象
id(i)==id(k)#False(因为这是两个独立的对象)

id(i[0])==id(k[0])#True(作为同一位置的参考,对吗?

i[0]=100

id(i[0])==id(k[0])#False(该loc中的值为什么会改变?

它更改了,因为您在前一行中更改了它
i[0]
指向
10
,但您将其更改为指向
100
。因此,
i[0]
k[0]
现在不再指向同一点

指针(引用)是一种方式<代码>10不知道指向它的是什么。
100也没有。它们只是内存中的位置。因此,如果您更改
i
的第一个元素指向的位置,
k
不在乎(因为
k
i
不是同一个引用)
k
的第一个元素仍然指向它一直指向的东西

id(i[:])==id(k[:])#True(如果元素刚刚更改,为什么仍然是True?

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

>>> 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的一些微妙之处有关,这里有深入的回答:

长话短说,当你说
id([1,2,3,4,5])==id([1,2,3])
时,首先发生的事情是我们创建
[1,2,3,4,5]
。然后我们通过调用
id
获取它在内存中的位置。但是,
[1,2,3,4,5]
是匿名的,因此垃圾收集器会立即回收它。然后,我们创建另一个匿名对象,
[1,2,3]
,CPython碰巧决定它应该放在刚刚清理过的地方<代码>[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]
a[0]
不再指向同一个位置。

int
s是不可变的对象,所以您将一个新对象设置为
i[0]
。为什么希望
i[0]
仍然指向
k[0]
?这两个列表是不同的,因此一个列表中的更新不会反映在其他列表中。只要没有嵌套数组,浅层副本与深层副本相同。@sirgopythonjavacpprubythe3d哦,这很有意义。你能解释一下为什么在浅拷贝示例中
id(i[:])==id(k[:])
是真的(即使在k有一个新元素之后)?
id(i[:])==id(k[:])#真的(如果一个元素刚刚更改,为什么这仍然是真的?
。这可能是一个cpython实现细节<列表的code>id基于内存地址,该地址可能会被重用,因为
i[:]
会立即被垃圾收集。这两个列表不是同一个对象。@Ani Menon Welcome“在浅复制中,不可变对象被复制,但对于所有可变对象,它们的引用都被复制。”非真正的浅复制对可变和不可变对象执行相同的操作objects@juanpa.arrivillaga请review@AniMenon好极了,很高兴能帮上忙!