Home | History | Annotate | Download | only in Lib
      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 it 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 import weakref
     53 from copyreg import dispatch_table
     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", "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     cls = type(x)
     73 
     74     copier = _copy_dispatch.get(cls)
     75     if copier:
     76         return copier(x)
     77 
     78     try:
     79         issc = issubclass(cls, type)
     80     except TypeError: # cls is not a class
     81         issc = False
     82     if issc:
     83         # treat it as a regular class:
     84         return _copy_immutable(x)
     85 
     86     copier = getattr(cls, "__copy__", None)
     87     if copier:
     88         return copier(x)
     89 
     90     reductor = dispatch_table.get(cls)
     91     if reductor:
     92         rv = reductor(x)
     93     else:
     94         reductor = getattr(x, "__reduce_ex__", None)
     95         if reductor:
     96             rv = reductor(4)
     97         else:
     98             reductor = getattr(x, "__reduce__", None)
     99             if reductor:
    100                 rv = reductor()
    101             else:
    102                 raise Error("un(shallow)copyable object of type %s" % cls)
    103 
    104     if isinstance(rv, str):
    105         return x
    106     return _reconstruct(x, None, *rv)
    107 
    108 
    109 _copy_dispatch = d = {}
    110 
    111 def _copy_immutable(x):
    112     return x
    113 for t in (type(None), int, float, bool, complex, str, tuple,
    114           bytes, frozenset, type, range, slice,
    115           types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
    116           types.FunctionType, weakref.ref):
    117     d[t] = _copy_immutable
    118 t = getattr(types, "CodeType", None)
    119 if t is not None:
    120     d[t] = _copy_immutable
    121 
    122 d[list] = list.copy
    123 d[dict] = dict.copy
    124 d[set] = set.copy
    125 d[bytearray] = bytearray.copy
    126 
    127 if PyStringMap is not None:
    128     d[PyStringMap] = PyStringMap.copy
    129 
    130 del d, t
    131 
    132 def deepcopy(x, memo=None, _nil=[]):
    133     """Deep copy operation on arbitrary Python objects.
    134 
    135     See the module's __doc__ string for more info.
    136     """
    137 
    138     if memo is None:
    139         memo = {}
    140 
    141     d = id(x)
    142     y = memo.get(d, _nil)
    143     if y is not _nil:
    144         return y
    145 
    146     cls = type(x)
    147 
    148     copier = _deepcopy_dispatch.get(cls)
    149     if copier:
    150         y = copier(x, memo)
    151     else:
    152         try:
    153             issc = issubclass(cls, type)
    154         except TypeError: # cls is not a class (old Boost; see SF #502085)
    155             issc = 0
    156         if issc:
    157             y = _deepcopy_atomic(x, memo)
    158         else:
    159             copier = getattr(x, "__deepcopy__", None)
    160             if copier:
    161                 y = copier(memo)
    162             else:
    163                 reductor = dispatch_table.get(cls)
    164                 if reductor:
    165                     rv = reductor(x)
    166                 else:
    167                     reductor = getattr(x, "__reduce_ex__", None)
    168                     if reductor:
    169                         rv = reductor(4)
    170                     else:
    171                         reductor = getattr(x, "__reduce__", None)
    172                         if reductor:
    173                             rv = reductor()
    174                         else:
    175                             raise Error(
    176                                 "un(deep)copyable object of type %s" % cls)
    177                 if isinstance(rv, str):
    178                     y = x
    179                 else:
    180                     y = _reconstruct(x, memo, *rv)
    181 
    182     # If is its own copy, don't memoize.
    183     if y is not x:
    184         memo[d] = y
    185         _keep_alive(x, memo) # Make sure x lives at least as long as d
    186     return y
    187 
    188 _deepcopy_dispatch = d = {}
    189 
    190 def _deepcopy_atomic(x, memo):
    191     return x
    192 d[type(None)] = _deepcopy_atomic
    193 d[type(Ellipsis)] = _deepcopy_atomic
    194 d[type(NotImplemented)] = _deepcopy_atomic
    195 d[int] = _deepcopy_atomic
    196 d[float] = _deepcopy_atomic
    197 d[bool] = _deepcopy_atomic
    198 d[complex] = _deepcopy_atomic
    199 d[bytes] = _deepcopy_atomic
    200 d[str] = _deepcopy_atomic
    201 try:
    202     d[types.CodeType] = _deepcopy_atomic
    203 except AttributeError:
    204     pass
    205 d[type] = _deepcopy_atomic
    206 d[types.BuiltinFunctionType] = _deepcopy_atomic
    207 d[types.FunctionType] = _deepcopy_atomic
    208 d[weakref.ref] = _deepcopy_atomic
    209 
    210 def _deepcopy_list(x, memo, deepcopy=deepcopy):
    211     y = []
    212     memo[id(x)] = y
    213     append = y.append
    214     for a in x:
    215         append(deepcopy(a, memo))
    216     return y
    217 d[list] = _deepcopy_list
    218 
    219 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
    220     y = [deepcopy(a, memo) for a in x]
    221     # We're not going to put the tuple in the memo, but it's still important we
    222     # check for it, in case the tuple contains recursive mutable structures.
    223     try:
    224         return memo[id(x)]
    225     except KeyError:
    226         pass
    227     for k, j in zip(x, y):
    228         if k is not j:
    229             y = tuple(y)
    230             break
    231     else:
    232         y = x
    233     return y
    234 d[tuple] = _deepcopy_tuple
    235 
    236 def _deepcopy_dict(x, memo, deepcopy=deepcopy):
    237     y = {}
    238     memo[id(x)] = y
    239     for key, value in x.items():
    240         y[deepcopy(key, memo)] = deepcopy(value, memo)
    241     return y
    242 d[dict] = _deepcopy_dict
    243 if PyStringMap is not None:
    244     d[PyStringMap] = _deepcopy_dict
    245 
    246 def _deepcopy_method(x, memo): # Copy instance methods
    247     return type(x)(x.__func__, deepcopy(x.__self__, memo))
    248 d[types.MethodType] = _deepcopy_method
    249 
    250 del d
    251 
    252 def _keep_alive(x, memo):
    253     """Keeps a reference to the object x in the memo.
    254 
    255     Because we remember objects by their id, we have
    256     to assure that possibly temporary objects are kept
    257     alive by referencing them.
    258     We store a reference at the id of the memo, which should
    259     normally not be used unless someone tries to deepcopy
    260     the memo itself...
    261     """
    262     try:
    263         memo[id(memo)].append(x)
    264     except KeyError:
    265         # aha, this is the first one :-)
    266         memo[id(memo)]=[x]
    267 
    268 def _reconstruct(x, memo, func, args,
    269                  state=None, listiter=None, dictiter=None,
    270                  deepcopy=deepcopy):
    271     deep = memo is not None
    272     if deep and args:
    273         args = (deepcopy(arg, memo) for arg in args)
    274     y = func(*args)
    275     if deep:
    276         memo[id(x)] = y
    277 
    278     if state is not None:
    279         if deep:
    280             state = deepcopy(state, memo)
    281         if hasattr(y, '__setstate__'):
    282             y.__setstate__(state)
    283         else:
    284             if isinstance(state, tuple) and len(state) == 2:
    285                 state, slotstate = state
    286             else:
    287                 slotstate = None
    288             if state is not None:
    289                 y.__dict__.update(state)
    290             if slotstate is not None:
    291                 for key, value in slotstate.items():
    292                     setattr(y, key, value)
    293 
    294     if listiter is not None:
    295         if deep:
    296             for item in listiter:
    297                 item = deepcopy(item, memo)
    298                 y.append(item)
    299         else:
    300             for item in listiter:
    301                 y.append(item)
    302     if dictiter is not None:
    303         if deep:
    304             for key, value in dictiter:
    305                 key = deepcopy(key, memo)
    306                 value = deepcopy(value, memo)
    307                 y[key] = value
    308         else:
    309             for key, value in dictiter:
    310                 y[key] = value
    311     return y
    312 
    313 del types, weakref, PyStringMap
    314