操作之灵魂——拷贝
首先需要搞清楚两个概念:赋值
和引用
,对于操作 target = source:
赋值操作:程序先新建对象target,然后将source的值拷贝到target中。这里,target和source值相同,但是它们是两个完全不同的对象。
引用操作:程序直接将target指向source,也就是说target和source是同一个对象,target只不过是source的一个别名。
python中没有赋值,只有引用。
1 | 12 source = |
如果我们想拷贝一个对象,而不仅仅是创建一个引用,那么该如何操作呢?万能的python提供了两种拷贝机制浅拷贝(shallow copy)、深拷贝(deep copy)
供我们选择,浅拷贝和深拷贝的唯一区别在于对嵌套对象的拷贝处理上。
Function | Description |
---|---|
copy.copy(x) | Return a shallow copy of x. |
copy.deepcopy(x) | Return a deep copy of x. |
exception copy.error | Raised for module specific errors. |
简单引用:浅拷贝
对于嵌套对象比如说source = [1, 2, [3, 4]],浅拷贝创建新的列表对象target,target中的所有元素均是source中元素的引用,也就是说target中的元素只是source中元素的别名。
切片操作[start:end]
属于浅拷贝。
1 | 1, 2, [3, 4]] source = [ |
递归拷贝:深拷贝
大多时候有浅拷贝就足够了,但是某些情况下深拷贝仍有着举足轻重的作用。
深拷贝,其实就是递归拷贝。也就是说对于嵌套对象比如说source = [1, 2, [3, 4]],深拷贝时创建新的列表对象target,然后递归
地将source中的所有对象均拷贝到target中。即如果source中的元素是列表、字典等,那么python将拷贝这些列表、字典中的对象到target中去,就这样迭代下去,直到不存在嵌套结构。
1 | 1, 2, [3, 4]] source = [ |
深拷贝存在两个问题:
- 对一个递归对象进行深拷贝会导致递归循环。比如values = [values, 2];
- 由于深拷贝要拷贝所有对象,因此有时候会拷贝多余的内容,比如管理用的数据结构应该在不同拷贝间共享。
不过_deepcopy()_
函数提供了两个解决方案避免以上问题:
- 拷贝过程中维护一个备忘字典”memo”,字典中存放已经拷贝过的对象;
- 允许用户在自定义的类中重写拷贝操作或重写要拷贝的组件。