1 | from __future__ import print_function # for OPy compiler
|
2 | """Generic (shallow and deep) copying operations.
|
3 |
|
4 | Interface summary:
|
5 |
|
6 | import copy
|
7 |
|
8 | x = copy.copy(y) # make a shallow copy of y
|
9 | x = copy.deepcopy(y) # make a deep copy of y
|
10 |
|
11 | For module specific errors, copy.Error is raised.
|
12 |
|
13 | The difference between shallow and deep copying is only relevant for
|
14 | compound objects (objects that contain other objects, like lists or
|
15 | class instances).
|
16 |
|
17 | - A shallow copy constructs a new compound object and then (to the
|
18 | extent possible) inserts *the same objects* into it that the
|
19 | original contains.
|
20 |
|
21 | - A deep copy constructs a new compound object and then, recursively,
|
22 | inserts *copies* into it of the objects found in the original.
|
23 |
|
24 | Two problems often exist with deep copy operations that don't exist
|
25 | with shallow copy operations:
|
26 |
|
27 | a) recursive objects (compound objects that, directly or indirectly,
|
28 | contain a reference to themselves) may cause a recursive loop
|
29 |
|
30 | b) because deep copy copies *everything* it may copy too much, e.g.
|
31 | administrative data structures that should be shared even between
|
32 | copies
|
33 |
|
34 | Python's deep copy operation avoids these problems by:
|
35 |
|
36 | a) keeping a table of objects already copied during the current
|
37 | copying pass
|
38 |
|
39 | b) letting user-defined classes override the copying operation or the
|
40 | set of components copied
|
41 |
|
42 | This version does not copy types like module, class, function, method,
|
43 | nor stack trace, stack frame, nor file, socket, window, nor array, nor
|
44 | any similar types.
|
45 |
|
46 | Classes can use the same interfaces to control copying that they use
|
47 | to control pickling: they can define methods called __getinitargs__(),
|
48 | __getstate__() and __setstate__(). See the documentation for module
|
49 | "pickle" for information on these methods.
|
50 | """
|
51 |
|
52 | import types
|
53 | import weakref
|
54 | from copy_reg import dispatch_table
|
55 |
|
56 | class Error(Exception):
|
57 | pass
|
58 | error = Error # backward compatibility
|
59 |
|
60 | try:
|
61 | from org.python.core import PyStringMap
|
62 | except ImportError:
|
63 | PyStringMap = None
|
64 |
|
65 | __all__ = ["Error", "copy", "deepcopy"]
|
66 |
|
67 | def copy(x):
|
68 | """Shallow copy operation on arbitrary Python objects.
|
69 |
|
70 | See the module's __doc__ string for more info.
|
71 | """
|
72 |
|
73 | cls = type(x)
|
74 |
|
75 | copier = _copy_dispatch.get(cls)
|
76 | if copier:
|
77 | return copier(x)
|
78 |
|
79 | copier = getattr(cls, "__copy__", None)
|
80 | if copier:
|
81 | return copier(x)
|
82 |
|
83 | reductor = dispatch_table.get(cls)
|
84 | if reductor:
|
85 | rv = reductor(x)
|
86 | else:
|
87 | reductor = getattr(x, "__reduce_ex__", None)
|
88 | if reductor:
|
89 | rv = reductor(2)
|
90 | else:
|
91 | reductor = getattr(x, "__reduce__", None)
|
92 | if reductor:
|
93 | rv = reductor()
|
94 | else:
|
95 | raise Error("un(shallow)copyable object of type %s" % cls)
|
96 |
|
97 | return _reconstruct(x, rv, 0)
|
98 |
|
99 |
|
100 | _copy_dispatch = d = {}
|
101 |
|
102 | def _copy_immutable(x):
|
103 | return x
|
104 | for t in (type(None), int, long, float, bool, str, tuple,
|
105 | frozenset, type, xrange, types.ClassType,
|
106 | types.BuiltinFunctionType, type(Ellipsis),
|
107 | types.FunctionType, weakref.ref):
|
108 | d[t] = _copy_immutable
|
109 | for name in ("ComplexType", "UnicodeType", "CodeType"):
|
110 | t = getattr(types, name, None)
|
111 | if t is not None:
|
112 | d[t] = _copy_immutable
|
113 |
|
114 | def _copy_with_constructor(x):
|
115 | return type(x)(x)
|
116 | for t in (list, dict, set):
|
117 | d[t] = _copy_with_constructor
|
118 |
|
119 | def _copy_with_copy_method(x):
|
120 | return x.copy()
|
121 | if PyStringMap is not None:
|
122 | d[PyStringMap] = _copy_with_copy_method
|
123 |
|
124 | def _copy_inst(x):
|
125 | if hasattr(x, '__copy__'):
|
126 | return x.__copy__()
|
127 | if hasattr(x, '__getinitargs__'):
|
128 | args = x.__getinitargs__()
|
129 | y = x.__class__(*args)
|
130 | else:
|
131 | y = _EmptyClass()
|
132 | y.__class__ = x.__class__
|
133 | if hasattr(x, '__getstate__'):
|
134 | state = x.__getstate__()
|
135 | else:
|
136 | state = x.__dict__
|
137 | if hasattr(y, '__setstate__'):
|
138 | y.__setstate__(state)
|
139 | else:
|
140 | y.__dict__.update(state)
|
141 | return y
|
142 | d[types.InstanceType] = _copy_inst
|
143 |
|
144 | del d
|
145 |
|
146 | def deepcopy(x, memo=None, _nil=[]):
|
147 | """Deep copy operation on arbitrary Python objects.
|
148 |
|
149 | See the module's __doc__ string for more info.
|
150 | """
|
151 |
|
152 | if memo is None:
|
153 | memo = {}
|
154 |
|
155 | d = id(x)
|
156 | y = memo.get(d, _nil)
|
157 | if y is not _nil:
|
158 | return y
|
159 |
|
160 | cls = type(x)
|
161 |
|
162 | copier = _deepcopy_dispatch.get(cls)
|
163 | if copier:
|
164 | y = copier(x, memo)
|
165 | else:
|
166 | try:
|
167 | issc = issubclass(cls, type)
|
168 | except TypeError: # cls is not a class (old Boost; see SF #502085)
|
169 | issc = 0
|
170 | if issc:
|
171 | y = _deepcopy_atomic(x, memo)
|
172 | else:
|
173 | copier = getattr(x, "__deepcopy__", None)
|
174 | if copier:
|
175 | y = copier(memo)
|
176 | else:
|
177 | reductor = dispatch_table.get(cls)
|
178 | if reductor:
|
179 | rv = reductor(x)
|
180 | else:
|
181 | reductor = getattr(x, "__reduce_ex__", None)
|
182 | if reductor:
|
183 | rv = reductor(2)
|
184 | else:
|
185 | reductor = getattr(x, "__reduce__", None)
|
186 | if reductor:
|
187 | rv = reductor()
|
188 | else:
|
189 | raise Error(
|
190 | "un(deep)copyable object of type %s" % cls)
|
191 | y = _reconstruct(x, rv, 1, memo)
|
192 |
|
193 | memo[d] = y
|
194 | _keep_alive(x, memo) # Make sure x lives at least as long as d
|
195 | return y
|
196 |
|
197 | _deepcopy_dispatch = d = {}
|
198 |
|
199 | def _deepcopy_atomic(x, memo):
|
200 | return x
|
201 | d[type(None)] = _deepcopy_atomic
|
202 | d[type(Ellipsis)] = _deepcopy_atomic
|
203 | d[int] = _deepcopy_atomic
|
204 | d[long] = _deepcopy_atomic
|
205 | d[float] = _deepcopy_atomic
|
206 | d[bool] = _deepcopy_atomic
|
207 | try:
|
208 | d[complex] = _deepcopy_atomic
|
209 | except NameError:
|
210 | pass
|
211 | d[str] = _deepcopy_atomic
|
212 | try:
|
213 | d[unicode] = _deepcopy_atomic
|
214 | except NameError:
|
215 | pass
|
216 | try:
|
217 | d[types.CodeType] = _deepcopy_atomic
|
218 | except AttributeError:
|
219 | pass
|
220 | d[type] = _deepcopy_atomic
|
221 | d[xrange] = _deepcopy_atomic
|
222 | d[types.ClassType] = _deepcopy_atomic
|
223 | d[types.BuiltinFunctionType] = _deepcopy_atomic
|
224 | d[types.FunctionType] = _deepcopy_atomic
|
225 | d[weakref.ref] = _deepcopy_atomic
|
226 |
|
227 | def _deepcopy_list(x, memo):
|
228 | y = []
|
229 | memo[id(x)] = y
|
230 | for a in x:
|
231 | y.append(deepcopy(a, memo))
|
232 | return y
|
233 | d[list] = _deepcopy_list
|
234 |
|
235 | def _deepcopy_tuple(x, memo):
|
236 | y = []
|
237 | for a in x:
|
238 | y.append(deepcopy(a, memo))
|
239 | d = id(x)
|
240 | try:
|
241 | return memo[d]
|
242 | except KeyError:
|
243 | pass
|
244 | for i in range(len(x)):
|
245 | if x[i] is not y[i]:
|
246 | y = tuple(y)
|
247 | break
|
248 | else:
|
249 | y = x
|
250 | memo[d] = y
|
251 | return y
|
252 | d[tuple] = _deepcopy_tuple
|
253 |
|
254 | def _deepcopy_dict(x, memo):
|
255 | y = {}
|
256 | memo[id(x)] = y
|
257 | for key, value in x.iteritems():
|
258 | y[deepcopy(key, memo)] = deepcopy(value, memo)
|
259 | return y
|
260 | d[dict] = _deepcopy_dict
|
261 | if PyStringMap is not None:
|
262 | d[PyStringMap] = _deepcopy_dict
|
263 |
|
264 | def _deepcopy_method(x, memo): # Copy instance methods
|
265 | return type(x)(x.im_func, deepcopy(x.im_self, memo), x.im_class)
|
266 | _deepcopy_dispatch[types.MethodType] = _deepcopy_method
|
267 |
|
268 | def _keep_alive(x, memo):
|
269 | """Keeps a reference to the object x in the memo.
|
270 |
|
271 | Because we remember objects by their id, we have
|
272 | to assure that possibly temporary objects are kept
|
273 | alive by referencing them.
|
274 | We store a reference at the id of the memo, which should
|
275 | normally not be used unless someone tries to deepcopy
|
276 | the memo itself...
|
277 | """
|
278 | try:
|
279 | memo[id(memo)].append(x)
|
280 | except KeyError:
|
281 | # aha, this is the first one :-)
|
282 | memo[id(memo)]=[x]
|
283 |
|
284 | def _deepcopy_inst(x, memo):
|
285 | if hasattr(x, '__deepcopy__'):
|
286 | return x.__deepcopy__(memo)
|
287 | if hasattr(x, '__getinitargs__'):
|
288 | args = x.__getinitargs__()
|
289 | args = deepcopy(args, memo)
|
290 | y = x.__class__(*args)
|
291 | else:
|
292 | y = _EmptyClass()
|
293 | y.__class__ = x.__class__
|
294 | memo[id(x)] = y
|
295 | if hasattr(x, '__getstate__'):
|
296 | state = x.__getstate__()
|
297 | else:
|
298 | state = x.__dict__
|
299 | state = deepcopy(state, memo)
|
300 | if hasattr(y, '__setstate__'):
|
301 | y.__setstate__(state)
|
302 | else:
|
303 | y.__dict__.update(state)
|
304 | return y
|
305 | d[types.InstanceType] = _deepcopy_inst
|
306 |
|
307 | def _reconstruct(x, info, deep, memo=None):
|
308 | if isinstance(info, str):
|
309 | return x
|
310 | assert isinstance(info, tuple)
|
311 | if memo is None:
|
312 | memo = {}
|
313 | n = len(info)
|
314 | assert n in (2, 3, 4, 5)
|
315 | callable, args = info[:2]
|
316 | if n > 2:
|
317 | state = info[2]
|
318 | else:
|
319 | state = None
|
320 | if n > 3:
|
321 | listiter = info[3]
|
322 | else:
|
323 | listiter = None
|
324 | if n > 4:
|
325 | dictiter = info[4]
|
326 | else:
|
327 | dictiter = None
|
328 | if deep:
|
329 | args = deepcopy(args, memo)
|
330 | y = callable(*args)
|
331 | memo[id(x)] = y
|
332 |
|
333 | if state is not None:
|
334 | if deep:
|
335 | state = deepcopy(state, memo)
|
336 | if hasattr(y, '__setstate__'):
|
337 | y.__setstate__(state)
|
338 | else:
|
339 | if isinstance(state, tuple) and len(state) == 2:
|
340 | state, slotstate = state
|
341 | else:
|
342 | slotstate = None
|
343 | if state is not None:
|
344 | y.__dict__.update(state)
|
345 | if slotstate is not None:
|
346 | for key, value in slotstate.iteritems():
|
347 | setattr(y, key, value)
|
348 |
|
349 | if listiter is not None:
|
350 | for item in listiter:
|
351 | if deep:
|
352 | item = deepcopy(item, memo)
|
353 | y.append(item)
|
354 | if dictiter is not None:
|
355 | for key, value in dictiter:
|
356 | if deep:
|
357 | key = deepcopy(key, memo)
|
358 | value = deepcopy(value, memo)
|
359 | y[key] = value
|
360 | return y
|
361 |
|
362 | del d
|
363 |
|
364 | del types
|
365 |
|
366 | # Helper for instance creation without calling __init__
|
367 | class _EmptyClass:
|
368 | pass
|
369 |
|
370 | def _test():
|
371 | l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
|
372 | {'abc': 'ABC'}, (), [], {}]
|
373 | l1 = copy(l)
|
374 | print(l1==l)
|
375 | l1 = map(copy, l)
|
376 | print(l1==l)
|
377 | l1 = deepcopy(l)
|
378 | print(l1==l)
|
379 | class C:
|
380 | def __init__(self, arg=None):
|
381 | self.a = 1
|
382 | self.arg = arg
|
383 | if __name__ == '__main__':
|
384 | import sys
|
385 | file = sys.argv[0]
|
386 | else:
|
387 | file = __file__
|
388 | self.fp = open(file)
|
389 | self.fp.close()
|
390 | def __getstate__(self):
|
391 | return {'a': self.a, 'arg': self.arg}
|
392 | def __setstate__(self, state):
|
393 | for key, value in state.iteritems():
|
394 | setattr(self, key, value)
|
395 | def __deepcopy__(self, memo=None):
|
396 | new = self.__class__(deepcopy(self.arg, memo))
|
397 | new.a = self.a
|
398 | return new
|
399 | c = C('argument sketch')
|
400 | l.append(c)
|
401 | l2 = copy(l)
|
402 | print(l == l2)
|
403 | print(l)
|
404 | print(l2)
|
405 | l2 = deepcopy(l)
|
406 | print(l == l2)
|
407 | print(l)
|
408 | print(l2)
|
409 | l.append({l[1]: l, 'xyz': l[2]})
|
410 | l3 = copy(l)
|
411 | import repr
|
412 | print(map(repr.repr, l))
|
413 | print(map(repr.repr, l1))
|
414 | print(map(repr.repr, l2))
|
415 | print(map(repr.repr, l3))
|
416 | l3 = deepcopy(l)
|
417 | import repr
|
418 | print(map(repr.repr, l))
|
419 | print(map(repr.repr, l1))
|
420 | print(map(repr.repr, l2))
|
421 | print(map(repr.repr, l3))
|
422 | class odict(dict):
|
423 | def __init__(self, d = {}):
|
424 | self.a = 99
|
425 | dict.__init__(self, d)
|
426 | def __setitem__(self, k, i):
|
427 | dict.__setitem__(self, k, i)
|
428 | self.a
|
429 | o = odict({"A" : "B"})
|
430 | x = deepcopy(o)
|
431 | print((o, x))
|
432 |
|
433 | if __name__ == '__main__':
|
434 | _test()
|