Python浅拷贝和深拷贝
我正在尝试执行一个python脚本,该脚本应该告诉我们浅拷贝和深拷贝之间的区别Python浅拷贝和深拷贝,python,Python,我正在尝试执行一个python脚本,该脚本应该告诉我们浅拷贝和深拷贝之间的区别 In [142]: a3[0] = 1000 In [143]: map(id, a1) Out[143]: [26960216, 26960192, 26960168] In [144]: map(id, a2) Out[144]: [26960216, 26960192, 26960168] In [145]: map(id, a3) Out[145]: [39759800, 26960192, 26960
In [142]: a3[0] = 1000
In [143]: map(id, a1)
Out[143]: [26960216, 26960192, 26960168]
In [144]: map(id, a2)
Out[144]: [26960216, 26960192, 26960168]
In [145]: map(id, a3)
Out[145]: [39759800, 26960192, 26960168]
据我了解:
- 浅复制:创建对象并将其引用到原始文件中的内容
- 深度复制:创建一个对象,并将原始文件中的内容复制到该对象
a = [1,2,3]
print(id(a), id(a[0]), id(a[1]))
print("Lets check shallow copy first")
a1 = copy.copy(a)
print(id(a1), id(a1[0]), id(a1[1]))
a2 = copy.deepcopy(a)
print(id(a2), id(a2[0]), id(a2[1]))
输出:
steven@steven-Inspiron-3537:~/python-learning$ ./deepshallow.py
(139854551376528, 31777112, 31777088)
Lets check shallow copy first
(139854551485040, 31777112, 31777088)
(139854551378616, 31777112, 31777088)
你在这里看到的是,拷贝之间的整数是相同的,即使是深度拷贝。这是因为整数是“不可变的”,它们的标识基于它们的值和Python解释器的哈希设置 试试这个
a2[0] = 24
assert a2[0] != a1[0]
assert a2[0] != a[0]
a[0] = 72
assert a[0] != a1[0]
您将看到,即使是浅拷贝也不会受到影响。这是因为列表中的所有条目都是不可变的。对于更合适的示例,请尝试将列表或字典嵌套在彼此之间,并对它们运行相同的测试。在这种特定情况下,由于列表的元素是小整数,Python有一个内置机制来引用“相同”对象(整数)不允许对深度复制的列表进行更改,从而导致对其复制源的列表进行更改 下面是一个类似于您的整数的示例:
In [135]: import copy
In [136]: a1 = [1, 2, 3]
In [137]: a2 = copy.copy(a1)
In [138]: a3 = copy.deepcopy(a1)
In [139]: map(id, a1)
Out[139]: [26960216, 26960192, 26960168]
In [140]: map(id, a2)
Out[140]: [26960216, 26960192, 26960168]
In [141]: map(id, a3)
Out[141]: [26960216, 26960192, 26960168]
在这里,我们可以看到列表包含整数,所有整数都具有相同的id。让我们更改深层副本中的一个元素
In [142]: a3[0] = 1000
In [143]: map(id, a1)
Out[143]: [26960216, 26960192, 26960168]
In [144]: map(id, a2)
Out[144]: [26960216, 26960192, 26960168]
In [145]: map(id, a3)
Out[145]: [39759800, 26960192, 26960168]
现在,a3
的第一个条目有了一个新的id,而其他列表则保持不变。现在,让我们更改浅拷贝的第一个条目
In [146]: a2[0] = 1000
In [147]: map(id, a1)
Out[147]: [26960216, 26960192, 26960168]
In [148]: map(id, a2)
Out[148]: [39759200, 26960192, 26960168]
In [149]: map(id, a3)
Out[149]: [39759800, 26960192, 26960168]
请注意,整数1000作为a2
和a3
的第一个条目,其id值不同
原因是Python运行时实际上缓存了一些小整数和其他不可变对象,这意味着它们被引用的任何地方都是对单个缓存值的引用
这是:
当前的实现为-5到256之间的所有整数保留一个整数对象数组,当您在该范围内创建一个int时,实际上只返回对现有对象的引用。因此,应该可以更改1的值。我怀疑Python在本例中的行为是未定义的。:-)
要查看deepcopy
和copy
具有明显不同行为的示例,我们需要一些东西,其中deepcopy
对copy
的递归调用将产生不同的效果,而这不会发生在缓存的小整数上
让我们尝试使用列表列表,我们将修改内容,而不是突然更改最上面的列表元素之一所指的内容:
In [171]: a1 = [[1], [2], [3]]
In [172]: a2 = copy.copy(a1); a3 = copy.deepcopy(a1)
In [173]: a1
Out[173]: [[1], [2], [3]]
In [174]: a2
Out[174]: [[1], [2], [3]]
In [175]: map(id, a1)
Out[175]: [140608561277264, 140608561418040, 140608561277120]
In [176]: map(id, a2)
Out[176]: [140608561277264, 140608561418040, 140608561277120]
In [177]: a2[0][0] = 1000
In [178]: a1
Out[178]: [[1000], [2], [3]]
In [179]: a2
Out[179]: [[1000], [2], [3]]
In [180]: a3
Out[180]: [[1], [2], [3]]
In [181]: a3[1][0] = 1001
In [182]: a1
Out[182]: [[1000], [2], [3]]
In [183]: a2
Out[183]: [[1000], [2], [3]]
In [184]: a3
Out[184]: [[1], [1001], [3]]
这是不完全正确的。例如,如果您尝试
x=1000;y=1000;打印id(x);打印id(y)
您将看到x
和y
具有不同的id
值,即使它们引用同一个不可变对象1000
,但如果您尝试使用x=100;y=100(至少在CPython中),您将看到它们具有相同的id
值。我认为困惑在于为什么copy
的结果元素可以具有与其他元素相同的id
,即使是deepcopy
的情况,答案只是CPython的一个怪癖,即运行时缓存了一些整数。你是对的,我把id
与hash
和一些手动测试混为一谈。可能是重复的