copy-對象拷貝模塊;提供了淺拷貝和深拷貝複製對象的功能, 分別對應模塊中的兩個函數
copy()
和deepcopy()
。python
copy()
建立的 淺拷貝 是一個新的容器,它包含了對原始對象的內容的引用。也就是說僅拷貝父對象,不會拷貝對象的內部的子對象。即淺複製只複製對象自己,沒有複製該對象所引用的對象。好比,當建立一個列表對象的淺拷貝時,將構造一個新的列表,並將原始對象的元素添加給它。數據結構
import copy 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]))
my_list: [<__main__.MyClass object at 0x0000026DFF98D128>] dup: [<__main__.MyClass object at 0x0000026DFF98D128>] dup is my_list: False dup == my_list: True dup[0] is my_list[0]: True dup[0] == my_list[0]: True
上面的淺拷貝實例中,dup
是由 my_list
拷貝而來, 可是 MyClass
實例不會拷貝,因此 dup
列表與 my_list
中引用的是同一個對象。app
deepcopy()
建立的 深拷貝 是一個新的容器,它包含了對原始對象的內容的拷貝。深拷貝徹底拷貝了父對象及其子對象。即建立一個新的組合對象,同時遞歸地拷貝全部子對象,新的組合對象與原對象沒有任何關聯。雖然實際上會共享不可變的子對象,但不影響它們的相互獨立性。ide
將上面代碼換成 deepcopy()
,將會發現其中不一樣:函數
import copy 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]))
my_list: [<__main__.MyClass object at 0x000002442E47D128>] dup: [<__main__.MyClass object at 0x00000244352EF208>] dup is my_list: False dup == my_list: True dup[0] is my_list[0]: False dup[0] == my_list[0]: True
列表中的 MyClass
實例再也不是同一個的對象引用,而是從新複製了一份, 可是當兩個對象被比較時,它們的值仍然是相等的。code
能夠經過自定義 __copy__()
和 __deepcopy__()
方法來改變默認的拷貝行爲。orm
__copy()__
是一個無參數方法,它返回一個淺拷貝對象;對象
__deepcopy()__
接受一個備忘(memo)字典參數,返回一個深拷貝對象。須要進行深拷貝的成員屬性都應該傳遞給 copy.deepcopy()
,以及memo字典,以控制遞歸。(下面例子將解釋memo字典)。blog
下面的示例演示如何調用這些方法:遞歸
import copy 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)
__copy__() __deepcopy__({})
memo字典用於跟蹤已經拷貝的值,以免無限遞歸。
爲了不拷貝時有遞歸數據結構的問題, deepcopy()`` 使用一個字典來跟蹤已經拷貝的對象。這個字典被傳遞給
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
類包括一些基本的有向圖方法。能夠用一個名稱和它所鏈接的現有節點的列表來初始化一個實例。 add_connection()
方法用於設置雙向鏈接。它也被深拷貝操做符使用。
__deepcopy__()
方法打印了它的調用信息,並根據須要管理memo字典內容。它不會複製整個鏈接列表,而是建立一個新的列表,並將單個鏈接的副本添加進去。確保在每一個新節點被複制時更新memo字典,而且避免遞歸或重複拷貝節點。與之前同樣,該方法在完成時返回拷貝的對象。
Calling __deepcopy__ for Graph(name=root, id=2115579269360) Memo dictionary: (empty) Copying to new object Graph(name=root, id=2115695211072) Calling __deepcopy__ for Graph(name=a, id=2115695210904) Memo dictionary: Graph(name=root, id=2115579269360): Graph(name=root, id=2115695211072) Copying to new object Graph(name=a, id=2115695211184) Calling __deepcopy__ for Graph(name=root, id=2115579269360) Already copied to Graph(name=root, id=2115695211072) Calling __deepcopy__ for Graph(name=b, id=2115695210960) Memo dictionary: Graph(name=root, id=2115579269360): Graph(name=root, id=2115695211072) Graph(name=a, id=2115695210904): Graph(name=a, id=2115695211184) 2115579269360: Graph(name=root, id=2115695211072) 2115695219408: [Graph(name=root, id=2115579269360), Graph(name=a, id=2115695210904)] 2115695210904: Graph(name=a, id=2115695211184) Copying to new object Graph(name=b, id=2115695211240)
第二次遇到根節點時,若是一個節點被已拷貝時, __deepcopy__()
檢測遞歸,並從memo字典中重用現有的值,而不是建立一個新對象。