Python中的浅复制与深复制
Python中的标识、 相等性和别名
1.is,id和==
>>> charles = {'name': 'Charles L. Dodgson', 'born': 1832}
>>> lewis = charles ➊
>>> lewis is charles
True
>>> id(charles), id(lewis) ➋
(4300473992, 4300473992)
>>> lewis['balance'] = 950 ➌
>>> charles
{'name': 'Charles L. Dodgson', 'balance': 950, 'born': 1832}
说明:每个变量都有标识、 类型和值。 对象一旦创建, 它的标识绝不会变; 你可以把标识理解为对象在内存中的地址。 is 运算符比较两个对象的标识; id() 函数返回对象标识的整数表示 。id() 返回对象的内存地址 ,ID 一定是唯一的数值标注, 而且在对象的生命周期中绝不会变 。编程中很少使用 id() 函数。 标识最常使用 is 运算符检查, 而不是直接比较 ID。
和is之间的异同: 运算符比较两个对象的值(对象中保存的数据) , 而 is 比较对象的标识。
2.元组的相对不可变性
元组与多数 Python 集合(列表、 字典、 集, 等等) 一样, 保存的是对象的引用。 如果引用的元素是可变的, 即便元组本身不可变, 元素依然可变。 也就是说, 元组的不可变性其实是指 tuple 数据结构的物理内容(即保存的引用) 不可变, 与引用的对象无关。 而 str、 bytes 和 array.array 等单一类型序列是扁平的, 它们保存的不是引用, 而是在连续的内存中保存数据本身(字符、 字节和数字) 。
>>> t1 = (1, 2, [30, 40]) ➊
>>> t2 = (1, 2, [30, 40]) ➋
>>> t1 == t2 ➌
True
>>> id(t1[-1]) ➍
4302515784
>>> t1[-1].append(99) ➎
>>> t1
(1, 2, [30, 40, 99])
>>> id(t1[-1]) ➏
4302515784
>>> t1 == t2 ➐
False
3.默认做浅复制
>>> l1 = [3, [55, 44], (7, 8, 9)]
>>> l2 = list(l1) ➊
>>> l2
[3, [55, 44], (7, 8, 9)]
>>> l2 == l1 ➋
True
>>> l2 is l1 ➌
False
4.当元组中包含列表时的复制和修改
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1) # ➊
l1.append(100) # ➋
l1[1].remove(55) # ➌
print('l1:', l1)
print('l2:', l2)
l2[1] += [33, 22] # ➍
l2[2] += (10, 11) # ➎
print('l1:', l1)
print('l2:', l2)
输出结果:
l1: [3, [66, 44], (7, 8, 9), 100]
l2: [3, [66, 44], (7, 8, 9)]
l1: [3, [66, 44, 33, 22], (7, 8, 9), 100]
l2: [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]
使用http://www.pythontutor.com/visualize.html绘图程序运行过程:
step1:
step2:
step3:
step4:
step5:
从中可以简单但并不规范的总结为:当改变元组中的可变对象时,实际改变的是引用,而改变元组中的不可变对象时,改变的是单一对象的内容。
因此,浅复制容易操作, 但是得到的结果可能并不是你想要的
5.浅复制和深复制
copy 模块提供的 deepcopy 和 copy 函数能为任意对象做深复制和浅复制。
class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers)
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
>>> import copy
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
>>> bus2 = copy.copy(bus1)
>>> bus3 = copy.deepcopy(bus1)
>>> id(bus1), id(bus2), id(bus3)
(4301498296, 4301499416, 4301499752)
>>> bus1.drop('Bill')
>>> bus2.passengers
['Alice', 'Claire', 'David']
>>> id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)
(4302658568, 4302658568, 4302657800)
>>> bus3.passengers
['Alice', 'Bill', 'Claire', 'David']