Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
copy.py
Go to the documentation of this file.
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 # XXX need to support copy_reg here too...
52 
53 import types
54 
55 class Error(Exception):
56  pass
57 error = Error # backward compatibility
58 
59 try:
60  from org.python.core import PyStringMap
61 except ImportError:
62  PyStringMap = None
63 
64 __all__ = ["Error", "error", "copy", "deepcopy"]
65 
66 def copy(x):
67  """Shallow copy operation on arbitrary Python objects.
68 
69  See the module's __doc__ string for more info.
70  """
71 
72  try:
73  copierfunction = _copy_dispatch[type(x)]
74  except KeyError:
75  try:
76  copier = x.__copy__
77  except AttributeError:
78  try:
79  reductor = x.__reduce__
80  except AttributeError:
81  raise error, \
82  "un(shallow)copyable object of type %s" % type(x)
83  else:
84  y = _reconstruct(x, reductor(), 0)
85  else:
86  y = copier()
87  else:
88  y = copierfunction(x)
89  return y
90 
91 _copy_dispatch = d = {}
92 
93 def _copy_atomic(x):
94  return x
95 d[types.NoneType] = _copy_atomic
96 d[types.IntType] = _copy_atomic
97 d[types.LongType] = _copy_atomic
98 d[types.FloatType] = _copy_atomic
99 try:
100  d[types.ComplexType] = _copy_atomic
101 except AttributeError:
102  pass
103 d[types.StringType] = _copy_atomic
104 try:
105  d[types.UnicodeType] = _copy_atomic
106 except AttributeError:
107  pass
108 try:
109  d[types.CodeType] = _copy_atomic
110 except AttributeError:
111  pass
112 d[types.TypeType] = _copy_atomic
113 d[types.XRangeType] = _copy_atomic
114 d[types.ClassType] = _copy_atomic
115 
116 def _copy_list(x):
117  return x[:]
118 d[types.ListType] = _copy_list
119 
120 def _copy_tuple(x):
121  return x[:]
122 d[types.TupleType] = _copy_tuple
123 
124 def _copy_dict(x):
125  return x.copy()
126 d[types.DictionaryType] = _copy_dict
127 if PyStringMap is not None:
128  d[PyStringMap] = _copy_dict
129 
130 def _copy_inst(x):
131  if hasattr(x, '__copy__'):
132  return x.__copy__()
133  if hasattr(x, '__getinitargs__'):
134  args = x.__getinitargs__()
135  y = apply(x.__class__, args)
136  else:
137  y = _EmptyClass()
138  y.__class__ = x.__class__
139  if hasattr(x, '__getstate__'):
140  state = x.__getstate__()
141  else:
142  state = x.__dict__
143  if hasattr(y, '__setstate__'):
144  y.__setstate__(state)
145  else:
146  y.__dict__.update(state)
147  return y
148 d[types.InstanceType] = _copy_inst
149 
150 del d
151 
152 def deepcopy(x, memo = None):
153  """Deep copy operation on arbitrary Python objects.
154 
155  See the module's __doc__ string for more info.
156  """
157 
158  if memo is None:
159  memo = {}
160  d = id(x)
161  if memo.has_key(d):
162  return memo[d]
163  try:
164  copierfunction = _deepcopy_dispatch[type(x)]
165  except KeyError:
166  try:
167  copier = x.__deepcopy__
168  except AttributeError:
169  try:
170  reductor = x.__reduce__
171  except AttributeError:
172  raise error, \
173  "un-deep-copyable object of type %s" % type(x)
174  else:
175  y = _reconstruct(x, reductor(), 1, memo)
176  else:
177  y = copier(memo)
178  else:
179  y = copierfunction(x, memo)
180  memo[d] = y
181  return y
182 
183 _deepcopy_dispatch = d = {}
184 
185 def _deepcopy_atomic(x, memo):
186  return x
187 d[types.NoneType] = _deepcopy_atomic
188 d[types.IntType] = _deepcopy_atomic
189 d[types.LongType] = _deepcopy_atomic
190 d[types.FloatType] = _deepcopy_atomic
191 try:
192  d[types.ComplexType] = _deepcopy_atomic
193 except AttributeError:
194  pass
195 d[types.StringType] = _deepcopy_atomic
196 try:
197  d[types.UnicodeType] = _deepcopy_atomic
198 except AttributeError:
199  pass
200 try:
201  d[types.CodeType] = _deepcopy_atomic
202 except AttributeError:
203  pass
204 d[types.TypeType] = _deepcopy_atomic
205 d[types.XRangeType] = _deepcopy_atomic
206 
207 def _deepcopy_list(x, memo):
208  y = []
209  memo[id(x)] = y
210  for a in x:
211  y.append(deepcopy(a, memo))
212  return y
213 d[types.ListType] = _deepcopy_list
214 
215 def _deepcopy_tuple(x, memo):
216  y = []
217  for a in x:
218  y.append(deepcopy(a, memo))
219  d = id(x)
220  try:
221  return memo[d]
222  except KeyError:
223  pass
224  for i in range(len(x)):
225  if x[i] is not y[i]:
226  y = tuple(y)
227  break
228  else:
229  y = x
230  memo[d] = y
231  return y
232 d[types.TupleType] = _deepcopy_tuple
233 
234 def _deepcopy_dict(x, memo):
235  y = {}
236  memo[id(x)] = y
237  for key in x.keys():
238  y[deepcopy(key, memo)] = deepcopy(x[key], memo)
239  return y
240 d[types.DictionaryType] = _deepcopy_dict
241 if PyStringMap is not None:
242  d[PyStringMap] = _deepcopy_dict
243 
244 def _keep_alive(x, memo):
245  """Keeps a reference to the object x in the memo.
246 
247  Because we remember objects by their id, we have
248  to assure that possibly temporary objects are kept
249  alive by referencing them.
250  We store a reference at the id of the memo, which should
251  normally not be used unless someone tries to deepcopy
252  the memo itself...
253  """
254  try:
255  memo[id(memo)].append(x)
256  except KeyError:
257  # aha, this is the first one :-)
258  memo[id(memo)]=[x]
259 
260 def _deepcopy_inst(x, memo):
261  if hasattr(x, '__deepcopy__'):
262  return x.__deepcopy__(memo)
263  if hasattr(x, '__getinitargs__'):
264  args = x.__getinitargs__()
265  _keep_alive(args, memo)
266  args = deepcopy(args, memo)
267  y = apply(x.__class__, args)
268  else:
269  y = _EmptyClass()
270  y.__class__ = x.__class__
271  memo[id(x)] = y
272  if hasattr(x, '__getstate__'):
273  state = x.__getstate__()
274  _keep_alive(state, memo)
275  else:
276  state = x.__dict__
277  state = deepcopy(state, memo)
278  if hasattr(y, '__setstate__'):
279  y.__setstate__(state)
280  else:
281  y.__dict__.update(state)
282  return y
283 d[types.InstanceType] = _deepcopy_inst
284 
285 def _reconstruct(x, info, deep, memo=None):
286  if isinstance(info, str):
287  return x
288  assert isinstance(info, tuple)
289  if memo is None:
290  memo = {}
291  n = len(info)
292  assert n in (2, 3)
293  callable, args = info[:2]
294  if n > 2:
295  state = info[2]
296  else:
297  state = {}
298  if deep:
299  args = deepcopy(args, memo)
300  y = callable(*args)
301  if state:
302  if deep:
303  state = deepcopy(state, memo)
304  y.__dict__.update(state)
305  return y
306 
307 del d
308 
309 del types
310 
311 # Helper for instance creation without calling __init__
313  pass
314 
315 def _test():
316  l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
317  {'abc': 'ABC'}, (), [], {}]
318  l1 = copy(l)
319  print l1==l
320  l1 = map(copy, l)
321  print l1==l
322  l1 = deepcopy(l)
323  print l1==l
324  class C:
325  def __init__(self, arg=None):
326  self.a = 1
327  self.arg = arg
328  if __name__ == '__main__':
329  import sys
330  file = sys.argv[0]
331  else:
332  file = __file__
333  self.fp = open(file)
334  self.fp.close()
335  def __getstate__(self):
336  return {'a': self.a, 'arg': self.arg}
337  def __setstate__(self, state):
338  for key in state.keys():
339  setattr(self, key, state[key])
340  def __deepcopy__(self, memo = None):
341  new = self.__class__(deepcopy(self.arg, memo))
342  new.a = self.a
343  return new
344  c = C('argument sketch')
345  l.append(c)
346  l2 = copy(l)
347  print l == l2
348  print l
349  print l2
350  l2 = deepcopy(l)
351  print l == l2
352  print l
353  print l2
354  l.append({l[1]: l, 'xyz': l[2]})
355  l3 = copy(l)
356  import repr
357  print map(repr.repr, l)
358  print map(repr.repr, l1)
359  print map(repr.repr, l2)
360  print map(repr.repr, l3)
361  l3 = deepcopy(l)
362  import repr
363  print map(repr.repr, l)
364  print map(repr.repr, l1)
365  print map(repr.repr, l2)
366  print map(repr.repr, l3)
367 
368 if __name__ == '__main__':
369  _test()