1
"""Generic (shallow and deep) copying operations.
7
x = copy.copy(y) # make a shallow copy of y
8
x = copy.deepcopy(y) # make a deep copy of y
10
For module specific errors, copy.Error is raised.
12
The difference between shallow and deep copying is only relevant for
13
compound objects (objects that contain other objects, like lists or
16
- A shallow copy constructs a new compound object and then (to the
17
extent possible) inserts *the same objects* into it that the
20
- A deep copy constructs a new compound object and then, recursively,
21
inserts *copies* into it of the objects found in the original.
23
Two problems often exist with deep copy operations that don't exist
24
with shallow copy operations:
26
a) recursive objects (compound objects that, directly or indirectly,
27
contain a reference to themselves) may cause a recursive loop
29
b) because deep copy copies *everything* it may copy too much, e.g.
30
administrative data structures that should be shared even between
33
Python's deep copy operation avoids these problems by:
35
a) keeping a table of objects already copied during the current
38
b) letting user-defined classes override the copying operation or the
39
set of components copied
41
This version does not copy types like module, class, function, method,
42
nor stack trace, stack frame, nor file, socket, window, nor array, nor
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.
52
from copyreg import dispatch_table
54
class Error(Exception):
56
error = Error # backward compatibility
59
from org.python.core import PyStringMap
63
__all__ = ["Error", "copy", "deepcopy"]
66
"""Shallow copy operation on arbitrary Python objects.
68
See the module's __doc__ string for more info.
73
copier = _copy_dispatch.get(cls)
77
copier = getattr(cls, "__copy__", None)
81
reductor = dispatch_table.get(cls)
85
reductor = getattr(x, "__reduce_ex__", None)
89
reductor = getattr(x, "__reduce__", None)
93
raise Error("un(shallow)copyable object of type %s" % cls)
95
return _reconstruct(x, rv, 0)
98
_copy_dispatch = d = {}
100
def _copy_immutable(x):
102
for t in (type(None), int, float, bool, str, tuple,
103
frozenset, type, range,
104
types.BuiltinFunctionType, type(Ellipsis),
106
d[t] = _copy_immutable
107
t = getattr(types, "CodeType", None)
109
d[t] = _copy_immutable
110
for name in ("complex", "unicode"):
111
t = globals()['__builtins__'].get(name)
113
d[t] = _copy_immutable
115
def _copy_with_constructor(x):
117
for t in (list, dict, set):
118
d[t] = _copy_with_constructor
120
def _copy_with_copy_method(x):
122
if PyStringMap is not None:
123
d[PyStringMap] = _copy_with_copy_method
127
def deepcopy(x, memo=None, _nil=[]):
128
"""Deep copy operation on arbitrary Python objects.
130
See the module's __doc__ string for more info.
137
y = memo.get(d, _nil)
143
copier = _deepcopy_dispatch.get(cls)
148
issc = issubclass(cls, type)
149
except TypeError: # cls is not a class (old Boost; see SF #502085)
152
y = _deepcopy_atomic(x, memo)
154
copier = getattr(x, "__deepcopy__", None)
158
reductor = dispatch_table.get(cls)
162
reductor = getattr(x, "__reduce_ex__", None)
166
reductor = getattr(x, "__reduce__", None)
171
"un(deep)copyable object of type %s" % cls)
172
y = _reconstruct(x, rv, 1, memo)
175
_keep_alive(x, memo) # Make sure x lives at least as long as d
178
_deepcopy_dispatch = d = {}
180
def _deepcopy_atomic(x, memo):
182
d[type(None)] = _deepcopy_atomic
183
d[type(Ellipsis)] = _deepcopy_atomic
184
d[int] = _deepcopy_atomic
185
d[float] = _deepcopy_atomic
186
d[bool] = _deepcopy_atomic
188
d[complex] = _deepcopy_atomic
191
d[bytes] = _deepcopy_atomic
192
d[str] = _deepcopy_atomic
194
d[types.CodeType] = _deepcopy_atomic
195
except AttributeError:
197
d[type] = _deepcopy_atomic
198
d[range] = _deepcopy_atomic
199
d[types.BuiltinFunctionType] = _deepcopy_atomic
200
d[types.FunctionType] = _deepcopy_atomic
202
def _deepcopy_list(x, memo):
206
y.append(deepcopy(a, memo))
208
d[list] = _deepcopy_list
210
def _deepcopy_tuple(x, memo):
213
y.append(deepcopy(a, memo))
219
for i in range(len(x)):
227
d[tuple] = _deepcopy_tuple
229
def _deepcopy_dict(x, memo):
232
for key, value in x.items():
233
y[deepcopy(key, memo)] = deepcopy(value, memo)
235
d[dict] = _deepcopy_dict
236
if PyStringMap is not None:
237
d[PyStringMap] = _deepcopy_dict
239
def _keep_alive(x, memo):
240
"""Keeps a reference to the object x in the memo.
242
Because we remember objects by their id, we have
243
to assure that possibly temporary objects are kept
244
alive by referencing them.
245
We store a reference at the id of the memo, which should
246
normally not be used unless someone tries to deepcopy
250
memo[id(memo)].append(x)
252
# aha, this is the first one :-)
255
def _reconstruct(x, info, deep, memo=None):
256
if isinstance(info, str):
258
assert isinstance(info, tuple)
262
assert n in (2, 3, 4, 5)
263
callable, args = info[:2]
277
args = deepcopy(args, memo)
280
if listiter is not None:
281
for item in listiter:
283
item = deepcopy(item, memo)
285
if dictiter is not None:
286
for key, value in dictiter:
288
key = deepcopy(key, memo)
289
value = deepcopy(value, memo)
293
state = deepcopy(state, memo)
294
if hasattr(y, '__setstate__'):
295
y.__setstate__(state)
297
if isinstance(state, tuple) and len(state) == 2:
298
state, slotstate = state
301
if state is not None:
302
y.__dict__.update(state)
303
if slotstate is not None:
304
for key, value in slotstate.items():
305
setattr(y, key, value)
312
# Helper for instance creation without calling __init__
317
l = [None, 1, 2, 3.14, 'xyzzy', (1, 2), [3.14, 'abc'],
318
{'abc': 'ABC'}, (), [], {}]
326
def __init__(self, arg=None):
329
if __name__ == '__main__':
336
def __getstate__(self):
337
return {'a': self.a, 'arg': self.arg}
338
def __setstate__(self, state):
339
for key, value in state.items():
340
setattr(self, key, value)
341
def __deepcopy__(self, memo=None):
342
new = self.__class__(deepcopy(self.arg, memo))
345
c = C('argument sketch')
355
l.append({l[1]: l, 'xyz': l[2]})
358
print(map(reprlib.repr, l))
359
print(map(reprlib.repr, l1))
360
print(map(reprlib.repr, l2))
361
print(map(reprlib.repr, l3))
363
print(map(reprlib.repr, l))
364
print(map(reprlib.repr, l1))
365
print(map(reprlib.repr, l2))
366
print(map(reprlib.repr, l3))
368
if __name__ == '__main__':