浅复制深复制

对于数字/字符/元组这种不可变值,增加改变等操作都会改变它的引用。对于字典/列表/集合这种可变值,增加删除等操作都不会改变它的引用。

>>> a = 123 #数字int
>>> id(a)
140736147456080
>>> a = 1234
>>> id(a)
2612593870032 #引用已改变

>>> a = 'string' #字符string
>>> id(a)
2612623635440
>>> a += 'inhao'
>>> id(a)
2612626078256 #引用已改变

>>> a = [1,2,3] #列表list
>>> id(a)
2612625981320
>>> a.append(4)
>>> id(a)
2612625981320 #引用不改变

>>> a = {1:2} #字典dict
>>> id(a)
2612594022424
>>> a[2]=3
>>> id(a)
2612594022424 #引用不改变
  • 直接赋值:其实就是对象的引用(别名)。

  • 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。

  • 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

    例子:

>>> import copy
>>> a = [1,2,3,['a','b']]
>>> b = a #赋值
>>> c = copy.copy(a) #浅复制
>>> d = copy.deepcopy(a) #深复制
>>> a.append(4)
>>> a[3].append('c')
>>> a
[1, 2, 3, ['a', 'b', 'c'], 4]
>>> b
[1, 2, 3, ['a', 'b', 'c'], 4]
>>> c
[1, 2, 3, ['a', 'b', 'c']]
>>> d
[1, 2, 3, ['a', 'b']]

这里的列表b浅复制,只是复制了列表a中的引用,因为 a.append(4) 在原来的 a 中 ‘4’ 元素没有引用,所以列表 b 不会改变。(注意,如果输入命令 a[0]=1996,因为它原来复制的是 a[0] 的引用,而数值改变即 a[0]=1996 那么内存地址也变化了,所以列表 b 中仍不会改变),而列表 b 中的列表引用没有改变,还是列表 a 中列表['a','b']的引用,所以列表 a 中的列表改变,则列表 b 也随之改变。

>>> a = b = 123 #数字
>>> id(a),id(b)
(140736147456080, 140736147456080)
>>> b = 1996
>>> a,b,id(a),id(b)
(123, 1996, 140736147456080, 2991010350544)
>>> a = b = '123' #字符
>>> id(a),id(b)
(2991010494960, 2991010494960)
>>> b = '1996'
>>> a,b,id(a),id(b)
('123', '1996', 2991010494960, 2991010495344)

>>> a = '你好啊' #字符
>>> b = a
>>> c = a[:]
>>> import copy
>>> d = copy.copy(a)
>>> e = copy.deepcopy(a)
>>> a,b,c,d,e
('你好啊', '你好啊', '你好啊', '你好啊', '你好啊')
>>> id(a),id(b),id(c),id(d),id(e)
(2991008171280, 2991008171280, 2991008171280, 2991008171280, 2991008171280)

>>> a = 1996 #数字
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a,b,c,d
(1996, 1996, 1996, 1996)
>>> id(a),id(b),id(c),id(d)
(2991010350480, 2991010350480, 2991010350480, 2991010350480)

>>> a = [1,2,3] #列表
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(2315724705288, 2315724705288, 2315722286984, 2315724767112)
>>> a = {1,2,3} #集合
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(2315724733576, 2315724733576, 2315724873800, 2315724874248)
>>> a = {1:23} #字典
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(2315721054232, 2315721054232, 2315722298776, 2315724869704)

>>> a = 123 #数字
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(140736147456080, 140736147456080, 140736147456080, 140736147456080)
>>> a = '123' #字符
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(2315724810096, 2315724810096, 2315724810096, 2315724810096)
>>> a = (1,2,3) #元组
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> id(a),id(b),id(c),id(d)
(2315724708904, 2315724708904, 2315724708904, 2315724708904)

==和is

>>> a, b = 1, 1 #数字
>>> a == b
True
>>> a is b
True
>>> a, b= [1,2,3], [1,2,3] #列表list
>>> a is b
False
>>> a, b = (1,2,3), (1,2,3) #元组tuple
>>> a is b
False
>>> a, b = '123', '123' #字符string
>>> a is b
True

尽管 value 一样,但当 a 和 b 是 tuple,list,dict 或 set 型时,a is b为 False。

  • 数字和字符串时,a is b 为True.
    • 对于数字:python 初始化时会定义数字范围是-5~256的数值。在这个范围内的数值已经分配好了统一的内存地址。
    • 对于字符串:无论多么长的字符串都满足,但是不能有特殊字符。