Update functools section
[python.git] / Lib / copy.py
blob35c666f7dc0fa7aba77e89d42a213cb0000911c9
1 """Generic (shallow and deep) copying operations.
3 Interface summary:
5 import copy
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
14 class instances).
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.
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
31 copies
33 Python's deep copy operation avoids these problems by:
35 a) keeping a table of objects already copied during the current
36 copying pass
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
43 any similar types.
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 """
51 import types
52 from copy_reg import dispatch_table
54 class Error(Exception):
55 pass
56 error = Error # backward compatibility
58 try:
59 from org.python.core import PyStringMap
60 except ImportError:
61 PyStringMap = None
63 __all__ = ["Error", "copy", "deepcopy"]
65 def copy(x):
66 """Shallow copy operation on arbitrary Python objects.
68 See the module's __doc__ string for more info.
69 """
71 cls = type(x)
73 copier = _copy_dispatch.get(cls)
74 if copier:
75 return copier(x)
77 copier = getattr(cls, "__copy__", None)
78 if copier:
79 return copier(x)
81 reductor = dispatch_table.get(cls)
82 if reductor:
83 rv = reductor(x)
84 else:
85 reductor = getattr(x, "__reduce_ex__", None)
86 if reductor:
87 rv = reductor(2)
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)
95 return _reconstruct(x, rv, 0)
98 _copy_dispatch = d = {}
100 def _copy_immutable(x):
101 return x
102 for t in (type(None), int, long, float, bool, str, tuple,
103 frozenset, type, xrange, types.ClassType,
104 types.BuiltinFunctionType,
105 types.FunctionType):
106 d[t] = _copy_immutable
107 for name in ("ComplexType", "UnicodeType", "CodeType"):
108 t = getattr(types, name, None)
109 if t is not None:
110 d[t] = _copy_immutable
112 def _copy_with_constructor(x):
113 return type(x)(x)
114 for t in (list, dict, set):
115 d[t] = _copy_with_constructor
117 def _copy_with_copy_method(x):
118 return x.copy()
119 if PyStringMap is not None:
120 d[PyStringMap] = _copy_with_copy_method
122 def _copy_inst(x):
123 if hasattr(x, '__copy__'):
124 return x.__copy__()
125 if hasattr(x, '__getinitargs__'):
126 args = x.__getinitargs__()
127 y = x.__class__(*args)
128 else:
129 y = _EmptyClass()
130 y.__class__ = x.__class__
131 if hasattr(x, '__getstate__'):
132 state = x.__getstate__()
133 else:
134 state = x.__dict__
135 if hasattr(y, '__setstate__'):
136 y.__setstate__(state)
137 else:
138 y.__dict__.update(state)
139 return y
140 d[types.InstanceType] = _copy_inst
142 del d
144 def deepcopy(x, memo=None, _nil=[]):
145 """Deep copy operation on arbitrary Python objects.
147 See the module's __doc__ string for more info.
150 if memo is None:
151 memo = {}
153 d = id(x)
154 y = memo.get(d, _nil)
155 if y is not _nil:
156 return y
158 cls = type(x)
160 copier = _deepcopy_dispatch.get(cls)
161 if copier:
162 y = copier(x, memo)
163 else:
164 try:
165 issc = issubclass(cls, type)
166 except TypeError: # cls is not a class (old Boost; see SF #502085)
167 issc = 0
168 if issc:
169 y = _deepcopy_atomic(x, memo)
170 else:
171 copier = getattr(x, "__deepcopy__", None)
172 if copier:
173 y = copier(memo)
174 else:
175 reductor = dispatch_table.get(cls)
176 if reductor:
177 rv = reductor(x)
178 else:
179 reductor = getattr(x, "__reduce_ex__", None)
180 if reductor:
181 rv = reductor(2)
182 else:
183 reductor = getattr(x, "__reduce__", None)
184 if reductor:
185 rv = reductor()
186 else:
187 raise Error(
188 "un(deep)copyable object of type %s" % cls)
189 y = _reconstruct(x, rv, 1, memo)
191 memo[d] = y
192 _keep_alive(x, memo) # Make sure x lives at least as long as d
193 return y
195 _deepcopy_dispatch = d = {}
197 def _deepcopy_atomic(x, memo):
198 return x
199 d[type(None)] = _deepcopy_atomic
200 d[int] = _deepcopy_atomic
201 d[long] = _deepcopy_atomic
202 d[float] = _deepcopy_atomic
203 d[bool] = _deepcopy_atomic
204 try:
205 d[complex] = _deepcopy_atomic
206 except NameError:
207 pass
208 d[str] = _deepcopy_atomic
209 try:
210 d[unicode] = _deepcopy_atomic
211 except NameError:
212 pass
213 try:
214 d[types.CodeType] = _deepcopy_atomic
215 except AttributeError:
216 pass
217 d[type] = _deepcopy_atomic
218 d[xrange] = _deepcopy_atomic
219 d[types.ClassType] = _deepcopy_atomic
220 d[types.BuiltinFunctionType] = _deepcopy_atomic
221 d[types.FunctionType] = _deepcopy_atomic
223 def _deepcopy_list(x, memo):
224 y = []
225 memo[id(x)] = y
226 for a in x:
227 y.append(deepcopy(a, memo))
228 return y
229 d[list] = _deepcopy_list
231 def _deepcopy_tuple(x, memo):
232 y = []
233 for a in x:
234 y.append(deepcopy(a, memo))
235 d = id(x)
236 try:
237 return memo[d]
238 except KeyError:
239 pass
240 for i in range(len(x)):
241 if x[i] is not y[i]:
242 y = tuple(y)
243 break
244 else:
245 y = x
246 memo[d] = y
247 return y
248 d[tuple] = _deepcopy_tuple
250 def _deepcopy_dict(x, memo):
251 y = {}
252 memo[id(x)] = y
253 for key, value in x.iteritems():
254 y[deepcopy(key, memo)] = deepcopy(value, memo)
255 return y
256 d[dict] = _deepcopy_dict
257 if PyStringMap is not None:
258 d[PyStringMap] = _deepcopy_dict
260 def _keep_alive(x, memo):
261 """Keeps a reference to the object x in the memo.
263 Because we remember objects by their id, we have
264 to assure that possibly temporary objects are kept
265 alive by referencing them.
266 We store a reference at the id of the memo, which should
267 normally not be used unless someone tries to deepcopy
268 the memo itself...
270 try:
271 memo[id(memo)].append(x)
272 except KeyError:
273 # aha, this is the first one :-)
274 memo[id(memo)]=[x]
276 def _deepcopy_inst(x, memo):
277 if hasattr(x, '__deepcopy__'):
278 return x.__deepcopy__(memo)
279 if hasattr(x, '__getinitargs__'):
280 args = x.__getinitargs__()
281 args = deepcopy(args, memo)
282 y = x.__class__(*args)
283 else:
284 y = _EmptyClass()
285 y.__class__ = x.__class__
286 memo[id(x)] = y
287 if hasattr(x, '__getstate__'):
288 state = x.__getstate__()
289 else:
290 state = x.__dict__
291 state = deepcopy(state, memo)
292 if hasattr(y, '__setstate__'):
293 y.__setstate__(state)
294 else:
295 y.__dict__.update(state)
296 return y
297 d[types.InstanceType] = _deepcopy_inst
299 def _reconstruct(x, info, deep, memo=None):
300 if isinstance(info, str):
301 return x
302 assert isinstance(info, tuple)
303 if memo is None:
304 memo = {}
305 n = len(info)
306 assert n in (2, 3, 4, 5)
307 callable, args = info[:2]
308 if n > 2:
309 state = info[2]
310 else:
311 state = {}
312 if n > 3:
313 listiter = info[3]
314 else:
315 listiter = None
316 if n > 4:
317 dictiter = info[4]
318 else:
319 dictiter = None
320 if deep:
321 args = deepcopy(args, memo)
322 y = callable(*args)
323 memo[id(x)] = y
324 if listiter is not None:
325 for item in listiter:
326 if deep:
327 item = deepcopy(item, memo)
328 y.append(item)
329 if dictiter is not None:
330 for key, value in dictiter:
331 if deep:
332 key = deepcopy(key, memo)
333 value = deepcopy(value, memo)
334 y[key] = value
335 if state:
336 if deep:
337 state = deepcopy(state, memo)
338 if hasattr(y, '__setstate__'):
339 y.__setstate__(state)
340 else:
341 if isinstance(state, tuple) and len(state) == 2:
342 state, slotstate = state
343 else:
344 slotstate = None
345 if state is not None:
346 y.__dict__.update(state)
347 if slotstate is not None:
348 for key, value in slotstate.iteritems():
349 setattr(y, key, value)
350 return y
352 del d
354 del types
356 # Helper for instance creation without calling __init__
357 class _EmptyClass:
358 pass
360 def _test():
361 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
362 {'abc': 'ABC'}, (), [], {}]
363 l1 = copy(l)
364 print l1==l
365 l1 = map(copy, l)
366 print l1==l
367 l1 = deepcopy(l)
368 print l1==l
369 class C:
370 def __init__(self, arg=None):
371 self.a = 1
372 self.arg = arg
373 if __name__ == '__main__':
374 import sys
375 file = sys.argv[0]
376 else:
377 file = __file__
378 self.fp = open(file)
379 self.fp.close()
380 def __getstate__(self):
381 return {'a': self.a, 'arg': self.arg}
382 def __setstate__(self, state):
383 for key, value in state.iteritems():
384 setattr(self, key, value)
385 def __deepcopy__(self, memo=None):
386 new = self.__class__(deepcopy(self.arg, memo))
387 new.a = self.a
388 return new
389 c = C('argument sketch')
390 l.append(c)
391 l2 = copy(l)
392 print l == l2
393 print l
394 print l2
395 l2 = deepcopy(l)
396 print l == l2
397 print l
398 print l2
399 l.append({l[1]: l, 'xyz': l[2]})
400 l3 = copy(l)
401 import repr
402 print map(repr.repr, l)
403 print map(repr.repr, l1)
404 print map(repr.repr, l2)
405 print map(repr.repr, l3)
406 l3 = deepcopy(l)
407 import repr
408 print map(repr.repr, l)
409 print map(repr.repr, l1)
410 print map(repr.repr, l2)
411 print map(repr.repr, l3)
413 if __name__ == '__main__':
414 _test()