Python3标准库:copy复制对象
Posted 爱编程的小灰灰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python3标准库:copy复制对象相关的知识,希望对你有一定的参考价值。
1. copy复制对象
copy模块包括两个函数copy()和deepcopy(),用于复制现有的对象。
1.1 浅副本
copy()创建的浅副本(shallow copy)是一个新容器,其中填充了原对象内容的引用。建立list对象的一个浅副本时,会构造一个新的list,并将原对象的元素追加到这个list。
import copy import functools @functools.total_ordering class MyClass: def __init__(self, name): self.name = name def __eq__(self, other): return self.name == other.name def __gt__(self, other): return self.name > other.name a = MyClass(\'a\') my_list = [a] dup = copy.copy(my_list) print(\' my_list:\', my_list) print(\' dup:\', dup) print(\' dup is my_list:\', (dup is my_list)) print(\' dup == my_list:\', (dup == my_list)) print(\'dup[0] is my_list[0]:\', (dup[0] is my_list[0])) print(\'dup[0] == my_list[0]:\', (dup[0] == my_list[0]))
作为一个浅副本,并不会复制MyClass实例,所以dup列表中的引用会指向my_list中相同的对象。
1.2 深副本
deepcopy()创建的深副本是一个新容器,其中填充了原对象内容的副本。要建立一个list的深副本,会构造一个新的list,复制原列表的元素,然后将这些副本追加到新列表。
将前例中的copy()调用替换为deepcopy(),可以清楚地看出输出的不同。
import copy import functools @functools.total_ordering class MyClass: def __init__(self, name): self.name = name def __eq__(self, other): return self.name == other.name def __gt__(self, other): return self.name > other.name a = MyClass(\'a\') my_list = [a] dup = copy.deepcopy(my_list) print(\' my_list:\', my_list) print(\' dup:\', dup) print(\' dup is my_list:\', (dup is my_list)) print(\' dup == my_list:\', (dup == my_list)) print(\'dup[0] is my_list[0]:\', (dup[0] is my_list[0])) print(\'dup[0] == my_list[0]:\', (dup[0] == my_list[0]))
列表的第一个元素不再是相同的对象引用,不过比较这两个对象时,仍认为它们是相等的。
1.3 定制复制行为
可以使用特殊方法__copy__()和__deepcopy__()来控制如何建立副本。
调用__copy__()而不提供任何参数,这会返回对象的一个浅副本。
调用__deepcopy__(),并提供一个备忘字典,这会返回对象的一个深副本。所有需要深复制的成员属性都要连同备忘字典传递到copy.deepcopy()以控制递归(备忘字典将在后面更详细地解释)。
import copy import functools @functools.total_ordering class MyClass: def __init__(self, name): self.name = name def __eq__(self, other): return self.name == other.name def __gt__(self, other): return self.name > other.name def __copy__(self): print(\'__copy__()\') return MyClass(self.name) def __deepcopy__(self, memo): print(\'__deepcopy__({})\'.format(memo)) return MyClass(copy.deepcopy(self.name, memo)) a = MyClass(\'a\') sc = copy.copy(a) dc = copy.deepcopy(a)
备忘字典用于跟踪已复制的值,以避免无限递归。
1.4 深副本中的递归
为了避免复制递归数据结构可能带来的问题,deepcopy()使用了一个字典来跟踪已复制的对象。将这个字典传入__deepcopy__()方法,这样在该方法中也可以检查这个字典。
import copy class Graph: def __init__(self, name, connections): self.name = name self.connections = connections def add_connection(self, other): self.connections.append(other) def __repr__(self): return \'Graph(name={}, id={})\'.format( self.name, id(self)) def __deepcopy__(self, memo): print(\'\\nCalling __deepcopy__ for {!r}\'.format(self)) if self in memo: existing = memo.get(self) print(\' Already copied to {!r}\'.format(existing)) return existing print(\' Memo dictionary:\') if memo: for k, v in memo.items(): print(\' {}: {}\'.format(k, v)) else: print(\' (empty)\') dup = Graph(copy.deepcopy(self.name, memo), []) print(\' Copying to new object {}\'.format(dup)) memo[self] = dup for c in self.connections: dup.add_connection(copy.deepcopy(c, memo)) return dup root = Graph(\'root\', []) a = Graph(\'a\', [root]) b = Graph(\'b\', [a, root]) root.add_connection(a) root.add_connection(b) dup = copy.deepcopy(root)
Graph类包含一些基本的有向图方法。可以利用一个名和一个列表(包含已连接的现有节点)初始化一个graph实例。add_connection()方法用于建立双向连接。深复制操作符也用到了这个方法。
__deepcopy__()方法将打印消息来显示这个方法是如何调用的,并根据需要管理备忘字典内容。它不是复制整个连接列表,而是创建一个新列表,再把各个连接的副本追加到这个列表。这样可以确保复制各个新节点时会更新备忘字典,而避免递归问题或多于的节点副本。与前面一页,完成时会返回复制的对象。
以上是关于Python3标准库:copy复制对象的主要内容,如果未能解决你的问题,请参考以下文章