文章目录
赋值
赋值语句不复制对象,而是在目标和对象之间创建绑定 (bindings) 关系。可以想象成一个便利贴。
>>> a = [1, 2, 3]
>>> b = a
>>> id(a),id(b)
(2352320964872, 2352320964872)
>>> b.append(4)
>>> a, b
([1, 2, 3, 4], [1, 2, 3, 4])
>>> a.append(5)
>>> a, b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> id(a), id(b)
(2352320964872, 2352320964872)
浅拷贝和深拷贝
复制不可变数据类型(number/string/tuple)
深拷贝和浅拷贝都是同一个地址,和赋值“=”的情况一样
>>> s='1234'
>>> a=s
>>> b=copy.copy(s)
>>> c=copy.deepcopy(s)
>>> id(s),id(a),id(b),id(c)
(2352320790344, 2352320790344, 2352320790344, 2352320790344)
>>> a==s,b==s,c==s
(True, True, True)
>>> a is s,b is s,c is s
(True, True, True)
此时,如果改变a,b,c就会得到一个新的值,而不再指向s;同样,改变s,对a,b,c也不会造成影响
>>> a=a+'1'
>>> b=b+'2'
>>> c=c+'3'
>>> id(a),id(b),id(c),id(s)
(2352321344376, 2352320787992, 2352321372824, 2352320790344)
复制可变数据类型(list/dictionary)
浅拷贝
复制的对象中无复杂子对象
浅拷贝
原来值的改变不会影响浅拷贝的值,浅拷贝值的改变不会影响原来的值, 原来值的id和浅拷贝的值id不同
>>> s=[1,2,3]
>>> x=copy.copy(s)
>>> id(x),id(s)
(2352321310664, 2352321309896)
>>> x.append(4)
>>> x, s
([1, 2, 3, 4], [1, 2, 3])
>>> id(x), id(s)
(2352321310664, 2352321309896)
>>> s.append(5)
>>> x,s
([1, 2, 3, 4], [1, 2, 3, 5])
>>> id(x),id(s)
(2352321310664, 2352321309896)
赋值和浅拷贝的比较
当复制的对象是可变数据类型时,赋值结果和原来的值保持一致,浅拷贝和原来的值id不同
>>> s=[1,2,3]
>>> a=s
>>> b=copy.copy(s)
>>> a,b
([1, 2, 3], [1, 2, 3])
>>> id(a),id(b),id(s)
(2352321334088, 2352319165512, 2352321334088)
>>> a==s, b==s, a==b
(True, True, True)
>>> a is s, b is s, a is b
(True, False, False)
复制的对象中有复杂子对象(例如,列表中的一个子元素是列表)
浅拷贝
改变原来值中的复杂子对象的值,会影响浅拷贝的值,而且原来值和浅拷贝的值id不同
>>> s=[1,2,[1,2,3]]
>>> b=copy.copy(s)
>>> id(b), id(s)
(2352338267720, 2352321371080)
改变s中复杂子对象的值,会影响b
>>> s[2][2]=4
>>> b, s
([1, 2, [1, 2, 4]], [1, 2, [1, 2, 4]])
>>> id(b),id(s)
(2352338267720, 2352321371080)
改变b中复杂子对象的值,也会影响s
>>> b[2][2]=5
>>> b,s
Out[74]: ([1, 2, [1, 2, 5]], [1, 2, [1, 2, 5]])
改变s中非复杂子对象时,则对b没有影响
>>> s[0]=0
>>> b,s
([1, 2, [1, 2, 5]], [0, 2, [1, 2, 5]])
赋值
改变s中的任何元素,都会影响a,且a和s始终指向同一个地址
>>> s=[1,2,[1,2,3]]
>>> a=s
>>> id(a),id(s)
(2352320976072, 2352320976072)
>>> s[2][2]=4
>>> a,s
([1, 2, [1, 2, 4]], [1, 2, [1, 2, 4]])
>>> s[0]=0
>>> a,s
([0, 2, [1, 2, 4]], [0, 2, [1, 2, 4]])
>>> id(a),id(s)
(2352320976072, 2352320976072)
深拷贝
完全独立复制,包括内层列表和字典,id与原来的值不同,而且改变原来的值不会产生影响
>>> s=[1,2,[1,2,3]]
>>> c=copy.deepcopy(s)
>>> id(c),id(s)
(2352338272200, 2352320975368)
>>> s[2][2]=4
>>> c,s
([1, 2, [1, 2, 3]], [1, 2, [1, 2, 4]])
总结:
- 赋值操作相当于原来值的便利贴,无论什么情况下,都跟着原来的值保持一致;
- 在复制不可变数据类型,number/string/tuple(数值/字符串/元组)时,深拷贝和浅拷贝都是同一个地址,和赋值“=”的情况一样
- 在复制可变数据类型,list/dictionary(列表/字典)时,
对浅拷贝来说,
- 复制的对象中无复杂子对象
原来值的改变不会影响浅拷贝的值,浅拷贝值的改变不会影响原来的值,原来值的id和浅拷贝的值id不同
- 复制的对象中有复杂子对象
(例如,列表中的一个子元素是列表)
改变原来值中的复杂子对象的值,会影响浅拷贝的值,而且原来值的id和浅拷贝的值id不同
对深拷贝来说,
完全独立复制,包括内层列表和字典
stackoverflow上的一个回答
一个 浅拷贝 会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用 插入其中。
一个 深拷贝 会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本 插入。
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
赋值
d = c
print id(c) == id(d) # True - d is the same object as c
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
浅拷贝
d = copy.copy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
深拷贝
d = copy.deepcopy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # False - d[0] is now a new object
参考:
what-exactly-is-the-difference-between-shallow-copy-deepcopy-and-normal-assignm