赋值、浅拷贝和深拷贝的区别

赋值

赋值语句不复制对象,而是在目标和对象之间创建绑定 (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]])

总结:

  1. 赋值操作相当于原来值的便利贴,无论什么情况下,都跟着原来的值保持一致;
  2. 在复制不可变数据类型,number/string/tuple(数值/字符串/元组)时,深拷贝和浅拷贝都是同一个地址,和赋值“=”的情况一样
  3. 在复制可变数据类型,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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值