1 """Generic (shallow and deep) copying operations.
2
3 Interface summary:
4
5 import copy
6
7 x = copy.copy(y) # make a shallow copy of y
8 x = copy.deepcopy(y) # make a deep copy of y
9
10 For module specific errors, copy.Error is raised.
11
12 The difference between shallow and deep copying is only relevant for
13 compound objects (objects that contain other objects, like lists or
14 class instances).
15
16 - A shallow copy constructs a new compound object and then (to the
17 extent possible) inserts *the same objects* into it that the
18 original contains.
19
20 - A deep copy constructs a new compound object and then, recursively,
21 inserts *copies* into it of the objects found in the original.
22
23 Two problems often exist with deep copy operations that don't exist
24 with shallow copy operations:
25
26 a) recursive objects (compound objects that, directly or indirectly,
27 contain a reference to themselves) may cause a recursive loop
28
29 b) because deep copy copies *everything* it may copy too much, e.g.
30 administrative data structures that should be shared even between
31 copies
32
33 Python's deep copy operation avoids these problems by:
34
35 a) keeping a table of objects already copied during the current
36 copying pass
37
38 b) letting user-defined classes override the copying operation or the
39 set of components copied
40
41 This version does not copy types like module, class, function, method,
42 nor stack trace, stack frame, nor file, socket, window, nor any
43 similar types.
44
45 Classes can use the same interfaces to control copying that they use
46 to control pickling: they can define methods called __getinitargs__(),
47 __getstate__() and __setstate__(). See the documentation for module
48 "pickle" for information on these methods.
49 """
50
51 import types
52 import weakref
53 from copyreg import dispatch_table
54
55 class ESC[4;38;5;81mError(ESC[4;38;5;149mException):
56 pass
57 error = Error # backward compatibility
58
59 __all__ = ["Error", "copy", "deepcopy"]
60
61 def copy(x):
62 """Shallow copy operation on arbitrary Python objects.
63
64 See the module's __doc__ string for more info.
65 """
66
67 cls = type(x)
68
69 copier = _copy_dispatch.get(cls)
70 if copier:
71 return copier(x)
72
73 if issubclass(cls, type):
74 # treat it as a regular class:
75 return _copy_immutable(x)
76
77 copier = getattr(cls, "__copy__", None)
78 if copier is not None:
79 return copier(x)
80
81 reductor = dispatch_table.get(cls)
82 if reductor is not None:
83 rv = reductor(x)
84 else:
85 reductor = getattr(x, "__reduce_ex__", None)
86 if reductor is not None:
87 rv = reductor(4)
88 else:
89 reductor = getattr(x, "__reduce__", None)
90 if reductor:
91 rv = reductor()
92 else:
93 raise Error("un(shallow)copyable object of type %s" % cls)
94
95 if isinstance(rv, str):
96 return x
97 return _reconstruct(x, None, *rv)
98
99
100 _copy_dispatch = d = {}
101
102 def _copy_immutable(x):
103 return x
104 for t in (types.NoneType, int, float, bool, complex, str, tuple,
105 bytes, frozenset, type, range, slice, property,
106 types.BuiltinFunctionType, types.EllipsisType,
107 types.NotImplementedType, types.FunctionType, types.CodeType,
108 weakref.ref):
109 d[t] = _copy_immutable
110
111 d[list] = list.copy
112 d[dict] = dict.copy
113 d[set] = set.copy
114 d[bytearray] = bytearray.copy
115
116 del d, t
117
118 def deepcopy(x, memo=None, _nil=[]):
119 """Deep copy operation on arbitrary Python objects.
120
121 See the module's __doc__ string for more info.
122 """
123
124 if memo is None:
125 memo = {}
126
127 d = id(x)
128 y = memo.get(d, _nil)
129 if y is not _nil:
130 return y
131
132 cls = type(x)
133
134 copier = _deepcopy_dispatch.get(cls)
135 if copier is not None:
136 y = copier(x, memo)
137 else:
138 if issubclass(cls, type):
139 y = _deepcopy_atomic(x, memo)
140 else:
141 copier = getattr(x, "__deepcopy__", None)
142 if copier is not None:
143 y = copier(memo)
144 else:
145 reductor = dispatch_table.get(cls)
146 if reductor:
147 rv = reductor(x)
148 else:
149 reductor = getattr(x, "__reduce_ex__", None)
150 if reductor is not None:
151 rv = reductor(4)
152 else:
153 reductor = getattr(x, "__reduce__", None)
154 if reductor:
155 rv = reductor()
156 else:
157 raise Error(
158 "un(deep)copyable object of type %s" % cls)
159 if isinstance(rv, str):
160 y = x
161 else:
162 y = _reconstruct(x, memo, *rv)
163
164 # If is its own copy, don't memoize.
165 if y is not x:
166 memo[d] = y
167 _keep_alive(x, memo) # Make sure x lives at least as long as d
168 return y
169
170 _deepcopy_dispatch = d = {}
171
172 def _deepcopy_atomic(x, memo):
173 return x
174 d[types.NoneType] = _deepcopy_atomic
175 d[types.EllipsisType] = _deepcopy_atomic
176 d[types.NotImplementedType] = _deepcopy_atomic
177 d[int] = _deepcopy_atomic
178 d[float] = _deepcopy_atomic
179 d[bool] = _deepcopy_atomic
180 d[complex] = _deepcopy_atomic
181 d[bytes] = _deepcopy_atomic
182 d[str] = _deepcopy_atomic
183 d[types.CodeType] = _deepcopy_atomic
184 d[type] = _deepcopy_atomic
185 d[range] = _deepcopy_atomic
186 d[types.BuiltinFunctionType] = _deepcopy_atomic
187 d[types.FunctionType] = _deepcopy_atomic
188 d[weakref.ref] = _deepcopy_atomic
189 d[property] = _deepcopy_atomic
190
191 def _deepcopy_list(x, memo, deepcopy=deepcopy):
192 y = []
193 memo[id(x)] = y
194 append = y.append
195 for a in x:
196 append(deepcopy(a, memo))
197 return y
198 d[list] = _deepcopy_list
199
200 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
201 y = [deepcopy(a, memo) for a in x]
202 # We're not going to put the tuple in the memo, but it's still important we
203 # check for it, in case the tuple contains recursive mutable structures.
204 try:
205 return memo[id(x)]
206 except KeyError:
207 pass
208 for k, j in zip(x, y):
209 if k is not j:
210 y = tuple(y)
211 break
212 else:
213 y = x
214 return y
215 d[tuple] = _deepcopy_tuple
216
217 def _deepcopy_dict(x, memo, deepcopy=deepcopy):
218 y = {}
219 memo[id(x)] = y
220 for key, value in x.items():
221 y[deepcopy(key, memo)] = deepcopy(value, memo)
222 return y
223 d[dict] = _deepcopy_dict
224
225 def _deepcopy_method(x, memo): # Copy instance methods
226 return type(x)(x.__func__, deepcopy(x.__self__, memo))
227 d[types.MethodType] = _deepcopy_method
228
229 del d
230
231 def _keep_alive(x, memo):
232 """Keeps a reference to the object x in the memo.
233
234 Because we remember objects by their id, we have
235 to assure that possibly temporary objects are kept
236 alive by referencing them.
237 We store a reference at the id of the memo, which should
238 normally not be used unless someone tries to deepcopy
239 the memo itself...
240 """
241 try:
242 memo[id(memo)].append(x)
243 except KeyError:
244 # aha, this is the first one :-)
245 memo[id(memo)]=[x]
246
247 def _reconstruct(x, memo, func, args,
248 state=None, listiter=None, dictiter=None,
249 *, deepcopy=deepcopy):
250 deep = memo is not None
251 if deep and args:
252 args = (deepcopy(arg, memo) for arg in args)
253 y = func(*args)
254 if deep:
255 memo[id(x)] = y
256
257 if state is not None:
258 if deep:
259 state = deepcopy(state, memo)
260 if hasattr(y, '__setstate__'):
261 y.__setstate__(state)
262 else:
263 if isinstance(state, tuple) and len(state) == 2:
264 state, slotstate = state
265 else:
266 slotstate = None
267 if state is not None:
268 y.__dict__.update(state)
269 if slotstate is not None:
270 for key, value in slotstate.items():
271 setattr(y, key, value)
272
273 if listiter is not None:
274 if deep:
275 for item in listiter:
276 item = deepcopy(item, memo)
277 y.append(item)
278 else:
279 for item in listiter:
280 y.append(item)
281 if dictiter is not None:
282 if deep:
283 for key, value in dictiter:
284 key = deepcopy(key, memo)
285 value = deepcopy(value, memo)
286 y[key] = value
287 else:
288 for key, value in dictiter:
289 y[key] = value
290 return y
291
292 del types, weakref