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.
  • [get | view] (2006-01-16 21:28:38, 11.5 KB) [[attachment:copy-2.3.5.py]]
  • [get | view] (2006-01-18 08:55:22, 14.7 KB) [[attachment:moin15-384to386.diff]]
  • [get | view] (2006-01-11 14:13:44, 4.3 KB) [[attachment:traceback.html]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.