Attachment 'copy-2.3.5.py'
Download 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 in 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 array, nor
43 any 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 from copy_reg import dispatch_table
53
54 class Error(Exception):
55 pass
56 error = Error # backward compatibility
57
58 try:
59 from org.python.core import PyStringMap
60 except ImportError:
61 PyStringMap = None
62
63 __all__ = ["Error", "copy", "deepcopy"]
64
65 import inspect
66 def _getspecial(cls, name):
67 for basecls in inspect.getmro(cls):
68 try:
69 return basecls.__dict__[name]
70 except:
71 pass
72 else:
73 return None
74
75 def copy(x):
76 """Shallow copy operation on arbitrary Python objects.
77
78 See the module's __doc__ string for more info.
79 """
80
81 cls = type(x)
82
83 copier = _copy_dispatch.get(cls)
84 if copier:
85 return copier(x)
86
87 copier = _getspecial(cls, "__copy__")
88 if copier:
89 return copier(x)
90
91 reductor = dispatch_table.get(cls)
92 if reductor:
93 rv = reductor(x)
94 else:
95 reductor = getattr(x, "__reduce_ex__", None)
96 if reductor:
97 rv = reductor(2)
98 else:
99 reductor = getattr(x, "__reduce__", None)
100 if reductor:
101 rv = reductor()
102 else:
103 copier = getattr(x, "__copy__", None)
104 if copier:
105 return copier()
106 raise Error("un(shallow)copyable object of type %s" % cls)
107
108 return _reconstruct(x, rv, 0)
109
110
111 _copy_dispatch = d = {}
112
113 def _copy_atomic(x):
114 return x
115 d[types.NoneType] = _copy_atomic
116 d[types.IntType] = _copy_atomic
117 d[types.LongType] = _copy_atomic
118 d[types.FloatType] = _copy_atomic
119 d[types.BooleanType] = _copy_atomic
120 try:
121 d[types.ComplexType] = _copy_atomic
122 except AttributeError:
123 pass
124 d[types.StringType] = _copy_atomic
125 try:
126 d[types.UnicodeType] = _copy_atomic
127 except AttributeError:
128 pass
129 try:
130 d[types.CodeType] = _copy_atomic
131 except AttributeError:
132 pass
133 d[types.TypeType] = _copy_atomic
134 d[types.XRangeType] = _copy_atomic
135 d[types.ClassType] = _copy_atomic
136 d[types.BuiltinFunctionType] = _copy_atomic
137
138 def _copy_list(x):
139 return x[:]
140 d[types.ListType] = _copy_list
141
142 def _copy_tuple(x):
143 return x[:]
144 d[types.TupleType] = _copy_tuple
145
146 def _copy_dict(x):
147 return x.copy()
148 d[types.DictionaryType] = _copy_dict
149 if PyStringMap is not None:
150 d[PyStringMap] = _copy_dict
151
152 def _copy_inst(x):
153 if hasattr(x, '__copy__'):
154 return x.__copy__()
155 if hasattr(x, '__getinitargs__'):
156 args = x.__getinitargs__()
157 y = x.__class__(*args)
158 else:
159 y = _EmptyClass()
160 y.__class__ = x.__class__
161 if hasattr(x, '__getstate__'):
162 state = x.__getstate__()
163 else:
164 state = x.__dict__
165 if hasattr(y, '__setstate__'):
166 y.__setstate__(state)
167 else:
168 y.__dict__.update(state)
169 return y
170 d[types.InstanceType] = _copy_inst
171
172 del d
173
174 def deepcopy(x, memo=None, _nil=[]):
175 """Deep copy operation on arbitrary Python objects.
176
177 See the module's __doc__ string for more info.
178 """
179
180 if memo is None:
181 memo = {}
182
183 d = id(x)
184 y = memo.get(d, _nil)
185 if y is not _nil:
186 return y
187
188 cls = type(x)
189
190 copier = _deepcopy_dispatch.get(cls)
191 if copier:
192 y = copier(x, memo)
193 else:
194 try:
195 issc = issubclass(cls, type)
196 except TypeError: # cls is not a class (old Boost; see SF #502085)
197 issc = 0
198 if issc:
199 y = _deepcopy_atomic(x, memo)
200 else:
201 copier = _getspecial(cls, "__deepcopy__")
202 if copier:
203 y = copier(x, memo)
204 else:
205 reductor = dispatch_table.get(cls)
206 if reductor:
207 rv = reductor(x)
208 else:
209 reductor = getattr(x, "__reduce_ex__", None)
210 if reductor:
211 rv = reductor(2)
212 else:
213 reductor = getattr(x, "__reduce__", None)
214 if reductor:
215 rv = reductor()
216 else:
217 copier = getattr(x, "__deepcopy__", None)
218 if copier:
219 return copier(memo)
220 raise Error(
221 "un(deep)copyable object of type %s" % cls)
222 y = _reconstruct(x, rv, 1, memo)
223
224 memo[d] = y
225 _keep_alive(x, memo) # Make sure x lives at least as long as d
226 return y
227
228 _deepcopy_dispatch = d = {}
229
230 def _deepcopy_atomic(x, memo):
231 return x
232 d[types.NoneType] = _deepcopy_atomic
233 d[types.IntType] = _deepcopy_atomic
234 d[types.LongType] = _deepcopy_atomic
235 d[types.FloatType] = _deepcopy_atomic
236 d[types.BooleanType] = _deepcopy_atomic
237 try:
238 d[types.ComplexType] = _deepcopy_atomic
239 except AttributeError:
240 pass
241 d[types.StringType] = _deepcopy_atomic
242 try:
243 d[types.UnicodeType] = _deepcopy_atomic
244 except AttributeError:
245 pass
246 try:
247 d[types.CodeType] = _deepcopy_atomic
248 except AttributeError:
249 pass
250 d[types.TypeType] = _deepcopy_atomic
251 d[types.XRangeType] = _deepcopy_atomic
252 d[types.ClassType] = _deepcopy_atomic
253 d[types.BuiltinFunctionType] = _deepcopy_atomic
254
255 def _deepcopy_list(x, memo):
256 y = []
257 memo[id(x)] = y
258 for a in x:
259 y.append(deepcopy(a, memo))
260 return y
261 d[types.ListType] = _deepcopy_list
262
263 def _deepcopy_tuple(x, memo):
264 y = []
265 for a in x:
266 y.append(deepcopy(a, memo))
267 d = id(x)
268 try:
269 return memo[d]
270 except KeyError:
271 pass
272 for i in range(len(x)):
273 if x[i] is not y[i]:
274 y = tuple(y)
275 break
276 else:
277 y = x
278 memo[d] = y
279 return y
280 d[types.TupleType] = _deepcopy_tuple
281
282 def _deepcopy_dict(x, memo):
283 y = {}
284 memo[id(x)] = y
285 for key, value in x.iteritems():
286 y[deepcopy(key, memo)] = deepcopy(value, memo)
287 return y
288 d[types.DictionaryType] = _deepcopy_dict
289 if PyStringMap is not None:
290 d[PyStringMap] = _deepcopy_dict
291
292 def _keep_alive(x, memo):
293 """Keeps a reference to the object x in the memo.
294
295 Because we remember objects by their id, we have
296 to assure that possibly temporary objects are kept
297 alive by referencing them.
298 We store a reference at the id of the memo, which should
299 normally not be used unless someone tries to deepcopy
300 the memo itself...
301 """
302 try:
303 memo[id(memo)].append(x)
304 except KeyError:
305 # aha, this is the first one :-)
306 memo[id(memo)]=[x]
307
308 def _deepcopy_inst(x, memo):
309 if hasattr(x, '__deepcopy__'):
310 return x.__deepcopy__(memo)
311 if hasattr(x, '__getinitargs__'):
312 args = x.__getinitargs__()
313 args = deepcopy(args, memo)
314 y = x.__class__(*args)
315 else:
316 y = _EmptyClass()
317 y.__class__ = x.__class__
318 memo[id(x)] = y
319 if hasattr(x, '__getstate__'):
320 state = x.__getstate__()
321 else:
322 state = x.__dict__
323 state = deepcopy(state, memo)
324 if hasattr(y, '__setstate__'):
325 y.__setstate__(state)
326 else:
327 y.__dict__.update(state)
328 return y
329 d[types.InstanceType] = _deepcopy_inst
330
331 def _reconstruct(x, info, deep, memo=None):
332 if isinstance(info, str):
333 return x
334 assert isinstance(info, tuple)
335 if memo is None:
336 memo = {}
337 n = len(info)
338 assert n in (2, 3, 4, 5)
339 callable, args = info[:2]
340 if n > 2:
341 state = info[2]
342 else:
343 state = {}
344 if n > 3:
345 listiter = info[3]
346 else:
347 listiter = None
348 if n > 4:
349 dictiter = info[4]
350 else:
351 dictiter = None
352 if deep:
353 args = deepcopy(args, memo)
354 y = callable(*args)
355 memo[id(x)] = y
356 if listiter is not None:
357 for item in listiter:
358 if deep:
359 item = deepcopy(item, memo)
360 y.append(item)
361 if dictiter is not None:
362 for key, value in dictiter:
363 if deep:
364 key = deepcopy(key, memo)
365 value = deepcopy(value, memo)
366 y[key] = value
367 if state:
368 if deep:
369 state = deepcopy(state, memo)
370 if hasattr(y, '__setstate__'):
371 y.__setstate__(state)
372 else:
373 if isinstance(state, tuple) and len(state) == 2:
374 state, slotstate = state
375 else:
376 slotstate = None
377 if state is not None:
378 y.__dict__.update(state)
379 if slotstate is not None:
380 for key, value in slotstate.iteritems():
381 setattr(y, key, value)
382 return y
383
384 del d
385
386 del types
387
388 # Helper for instance creation without calling __init__
389 class _EmptyClass:
390 pass
391
392 def _test():
393 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
394 {'abc': 'ABC'}, (), [], {}]
395 l1 = copy(l)
396 print l1==l
397 l1 = map(copy, l)
398 print l1==l
399 l1 = deepcopy(l)
400 print l1==l
401 class C:
402 def __init__(self, arg=None):
403 self.a = 1
404 self.arg = arg
405 if __name__ == '__main__':
406 import sys
407 file = sys.argv[0]
408 else:
409 file = __file__
410 self.fp = open(file)
411 self.fp.close()
412 def __getstate__(self):
413 return {'a': self.a, 'arg': self.arg}
414 def __setstate__(self, state):
415 for key, value in state.iteritems():
416 setattr(self, key, value)
417 def __deepcopy__(self, memo=None):
418 new = self.__class__(deepcopy(self.arg, memo))
419 new.a = self.a
420 return new
421 c = C('argument sketch')
422 l.append(c)
423 l2 = copy(l)
424 print l == l2
425 print l
426 print l2
427 l2 = deepcopy(l)
428 print l == l2
429 print l
430 print l2
431 l.append({l[1]: l, 'xyz': l[2]})
432 l3 = copy(l)
433 import repr
434 print map(repr.repr, l)
435 print map(repr.repr, l1)
436 print map(repr.repr, l2)
437 print map(repr.repr, l3)
438 l3 = deepcopy(l)
439 import repr
440 print map(repr.repr, l)
441 print map(repr.repr, l1)
442 print map(repr.repr, l2)
443 print map(repr.repr, l3)
444
445 if __name__ == '__main__':
446 _test()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.