symbian-qemu-0.9.1-12/python-2.6.1/Lib/copy.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 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 def copy(x):
       
    66     """Shallow copy operation on arbitrary Python objects.
       
    67 
       
    68     See the module's __doc__ string for more info.
       
    69     """
       
    70 
       
    71     cls = type(x)
       
    72 
       
    73     copier = _copy_dispatch.get(cls)
       
    74     if copier:
       
    75         return copier(x)
       
    76 
       
    77     copier = getattr(cls, "__copy__", None)
       
    78     if copier:
       
    79         return copier(x)
       
    80 
       
    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)
       
    94 
       
    95     return _reconstruct(x, rv, 0)
       
    96 
       
    97 
       
    98 _copy_dispatch = d = {}
       
    99 
       
   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, type(Ellipsis),
       
   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
       
   111 
       
   112 def _copy_with_constructor(x):
       
   113     return type(x)(x)
       
   114 for t in (list, dict, set):
       
   115     d[t] = _copy_with_constructor
       
   116 
       
   117 def _copy_with_copy_method(x):
       
   118     return x.copy()
       
   119 if PyStringMap is not None:
       
   120     d[PyStringMap] = _copy_with_copy_method
       
   121 
       
   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
       
   141 
       
   142 del d
       
   143 
       
   144 def deepcopy(x, memo=None, _nil=[]):
       
   145     """Deep copy operation on arbitrary Python objects.
       
   146 
       
   147     See the module's __doc__ string for more info.
       
   148     """
       
   149 
       
   150     if memo is None:
       
   151         memo = {}
       
   152 
       
   153     d = id(x)
       
   154     y = memo.get(d, _nil)
       
   155     if y is not _nil:
       
   156         return y
       
   157 
       
   158     cls = type(x)
       
   159 
       
   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)
       
   190 
       
   191     memo[d] = y
       
   192     _keep_alive(x, memo) # Make sure x lives at least as long as d
       
   193     return y
       
   194 
       
   195 _deepcopy_dispatch = d = {}
       
   196 
       
   197 def _deepcopy_atomic(x, memo):
       
   198     return x
       
   199 d[type(None)] = _deepcopy_atomic
       
   200 d[type(Ellipsis)] = _deepcopy_atomic
       
   201 d[int] = _deepcopy_atomic
       
   202 d[long] = _deepcopy_atomic
       
   203 d[float] = _deepcopy_atomic
       
   204 d[bool] = _deepcopy_atomic
       
   205 try:
       
   206     d[complex] = _deepcopy_atomic
       
   207 except NameError:
       
   208     pass
       
   209 d[str] = _deepcopy_atomic
       
   210 try:
       
   211     d[unicode] = _deepcopy_atomic
       
   212 except NameError:
       
   213     pass
       
   214 try:
       
   215     d[types.CodeType] = _deepcopy_atomic
       
   216 except AttributeError:
       
   217     pass
       
   218 d[type] = _deepcopy_atomic
       
   219 d[xrange] = _deepcopy_atomic
       
   220 d[types.ClassType] = _deepcopy_atomic
       
   221 d[types.BuiltinFunctionType] = _deepcopy_atomic
       
   222 d[types.FunctionType] = _deepcopy_atomic
       
   223 
       
   224 def _deepcopy_list(x, memo):
       
   225     y = []
       
   226     memo[id(x)] = y
       
   227     for a in x:
       
   228         y.append(deepcopy(a, memo))
       
   229     return y
       
   230 d[list] = _deepcopy_list
       
   231 
       
   232 def _deepcopy_tuple(x, memo):
       
   233     y = []
       
   234     for a in x:
       
   235         y.append(deepcopy(a, memo))
       
   236     d = id(x)
       
   237     try:
       
   238         return memo[d]
       
   239     except KeyError:
       
   240         pass
       
   241     for i in range(len(x)):
       
   242         if x[i] is not y[i]:
       
   243             y = tuple(y)
       
   244             break
       
   245     else:
       
   246         y = x
       
   247     memo[d] = y
       
   248     return y
       
   249 d[tuple] = _deepcopy_tuple
       
   250 
       
   251 def _deepcopy_dict(x, memo):
       
   252     y = {}
       
   253     memo[id(x)] = y
       
   254     for key, value in x.iteritems():
       
   255         y[deepcopy(key, memo)] = deepcopy(value, memo)
       
   256     return y
       
   257 d[dict] = _deepcopy_dict
       
   258 if PyStringMap is not None:
       
   259     d[PyStringMap] = _deepcopy_dict
       
   260 
       
   261 def _keep_alive(x, memo):
       
   262     """Keeps a reference to the object x in the memo.
       
   263 
       
   264     Because we remember objects by their id, we have
       
   265     to assure that possibly temporary objects are kept
       
   266     alive by referencing them.
       
   267     We store a reference at the id of the memo, which should
       
   268     normally not be used unless someone tries to deepcopy
       
   269     the memo itself...
       
   270     """
       
   271     try:
       
   272         memo[id(memo)].append(x)
       
   273     except KeyError:
       
   274         # aha, this is the first one :-)
       
   275         memo[id(memo)]=[x]
       
   276 
       
   277 def _deepcopy_inst(x, memo):
       
   278     if hasattr(x, '__deepcopy__'):
       
   279         return x.__deepcopy__(memo)
       
   280     if hasattr(x, '__getinitargs__'):
       
   281         args = x.__getinitargs__()
       
   282         args = deepcopy(args, memo)
       
   283         y = x.__class__(*args)
       
   284     else:
       
   285         y = _EmptyClass()
       
   286         y.__class__ = x.__class__
       
   287     memo[id(x)] = y
       
   288     if hasattr(x, '__getstate__'):
       
   289         state = x.__getstate__()
       
   290     else:
       
   291         state = x.__dict__
       
   292     state = deepcopy(state, memo)
       
   293     if hasattr(y, '__setstate__'):
       
   294         y.__setstate__(state)
       
   295     else:
       
   296         y.__dict__.update(state)
       
   297     return y
       
   298 d[types.InstanceType] = _deepcopy_inst
       
   299 
       
   300 def _reconstruct(x, info, deep, memo=None):
       
   301     if isinstance(info, str):
       
   302         return x
       
   303     assert isinstance(info, tuple)
       
   304     if memo is None:
       
   305         memo = {}
       
   306     n = len(info)
       
   307     assert n in (2, 3, 4, 5)
       
   308     callable, args = info[:2]
       
   309     if n > 2:
       
   310         state = info[2]
       
   311     else:
       
   312         state = {}
       
   313     if n > 3:
       
   314         listiter = info[3]
       
   315     else:
       
   316         listiter = None
       
   317     if n > 4:
       
   318         dictiter = info[4]
       
   319     else:
       
   320         dictiter = None
       
   321     if deep:
       
   322         args = deepcopy(args, memo)
       
   323     y = callable(*args)
       
   324     memo[id(x)] = y
       
   325     if listiter is not None:
       
   326         for item in listiter:
       
   327             if deep:
       
   328                 item = deepcopy(item, memo)
       
   329             y.append(item)
       
   330     if dictiter is not None:
       
   331         for key, value in dictiter:
       
   332             if deep:
       
   333                 key = deepcopy(key, memo)
       
   334                 value = deepcopy(value, memo)
       
   335             y[key] = value
       
   336     if state:
       
   337         if deep:
       
   338             state = deepcopy(state, memo)
       
   339         if hasattr(y, '__setstate__'):
       
   340             y.__setstate__(state)
       
   341         else:
       
   342             if isinstance(state, tuple) and len(state) == 2:
       
   343                 state, slotstate = state
       
   344             else:
       
   345                 slotstate = None
       
   346             if state is not None:
       
   347                 y.__dict__.update(state)
       
   348             if slotstate is not None:
       
   349                 for key, value in slotstate.iteritems():
       
   350                     setattr(y, key, value)
       
   351     return y
       
   352 
       
   353 del d
       
   354 
       
   355 del types
       
   356 
       
   357 # Helper for instance creation without calling __init__
       
   358 class _EmptyClass:
       
   359     pass
       
   360 
       
   361 def _test():
       
   362     l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
       
   363          {'abc': 'ABC'}, (), [], {}]
       
   364     l1 = copy(l)
       
   365     print l1==l
       
   366     l1 = map(copy, l)
       
   367     print l1==l
       
   368     l1 = deepcopy(l)
       
   369     print l1==l
       
   370     class C:
       
   371         def __init__(self, arg=None):
       
   372             self.a = 1
       
   373             self.arg = arg
       
   374             if __name__ == '__main__':
       
   375                 import sys
       
   376                 file = sys.argv[0]
       
   377             else:
       
   378                 file = __file__
       
   379             self.fp = open(file)
       
   380             self.fp.close()
       
   381         def __getstate__(self):
       
   382             return {'a': self.a, 'arg': self.arg}
       
   383         def __setstate__(self, state):
       
   384             for key, value in state.iteritems():
       
   385                 setattr(self, key, value)
       
   386         def __deepcopy__(self, memo=None):
       
   387             new = self.__class__(deepcopy(self.arg, memo))
       
   388             new.a = self.a
       
   389             return new
       
   390     c = C('argument sketch')
       
   391     l.append(c)
       
   392     l2 = copy(l)
       
   393     print l == l2
       
   394     print l
       
   395     print l2
       
   396     l2 = deepcopy(l)
       
   397     print l == l2
       
   398     print l
       
   399     print l2
       
   400     l.append({l[1]: l, 'xyz': l[2]})
       
   401     l3 = copy(l)
       
   402     import repr
       
   403     print map(repr.repr, l)
       
   404     print map(repr.repr, l1)
       
   405     print map(repr.repr, l2)
       
   406     print map(repr.repr, l3)
       
   407     l3 = deepcopy(l)
       
   408     import repr
       
   409     print map(repr.repr, l)
       
   410     print map(repr.repr, l1)
       
   411     print map(repr.repr, l2)
       
   412     print map(repr.repr, l3)
       
   413 
       
   414 if __name__ == '__main__':
       
   415     _test()