PyXR

c:\python24\lib \ copy.py



0001 """Generic (shallow and deep) copying operations.
0002 
0003 Interface summary:
0004 
0005         import copy
0006 
0007         x = copy.copy(y)        # make a shallow copy of y
0008         x = copy.deepcopy(y)    # make a deep copy of y
0009 
0010 For module specific errors, copy.Error is raised.
0011 
0012 The difference between shallow and deep copying is only relevant for
0013 compound objects (objects that contain other objects, like lists or
0014 class instances).
0015 
0016 - A shallow copy constructs a new compound object and then (to the
0017   extent possible) inserts *the same objects* into in that the
0018   original contains.
0019 
0020 - A deep copy constructs a new compound object and then, recursively,
0021   inserts *copies* into it of the objects found in the original.
0022 
0023 Two problems often exist with deep copy operations that don't exist
0024 with shallow copy operations:
0025 
0026  a) recursive objects (compound objects that, directly or indirectly,
0027     contain a reference to themselves) may cause a recursive loop
0028 
0029  b) because deep copy copies *everything* it may copy too much, e.g.
0030     administrative data structures that should be shared even between
0031     copies
0032 
0033 Python's deep copy operation avoids these problems by:
0034 
0035  a) keeping a table of objects already copied during the current
0036     copying pass
0037 
0038  b) letting user-defined classes override the copying operation or the
0039     set of components copied
0040 
0041 This version does not copy types like module, class, function, method,
0042 nor stack trace, stack frame, nor file, socket, window, nor array, nor
0043 any similar types.
0044 
0045 Classes can use the same interfaces to control copying that they use
0046 to control pickling: they can define methods called __getinitargs__(),
0047 __getstate__() and __setstate__().  See the documentation for module
0048 "pickle" for information on these methods.
0049 """
0050 
0051 import types
0052 from copy_reg import dispatch_table
0053 
0054 class Error(Exception):
0055     pass
0056 error = Error   # backward compatibility
0057 
0058 try:
0059     from org.python.core import PyStringMap
0060 except ImportError:
0061     PyStringMap = None
0062 
0063 __all__ = ["Error", "copy", "deepcopy"]
0064 
0065 def copy(x):
0066     """Shallow copy operation on arbitrary Python objects.
0067 
0068     See the module's __doc__ string for more info.
0069     """
0070 
0071     cls = type(x)
0072 
0073     copier = _copy_dispatch.get(cls)
0074     if copier:
0075         return copier(x)
0076 
0077     copier = getattr(cls, "__copy__", None)
0078     if copier:
0079         return copier(x)
0080 
0081     reductor = dispatch_table.get(cls)
0082     if reductor:
0083         rv = reductor(x)
0084     else:
0085         reductor = getattr(x, "__reduce_ex__", None)
0086         if reductor:
0087             rv = reductor(2)
0088         else:
0089             reductor = getattr(x, "__reduce__", None)
0090             if reductor:
0091                 rv = reductor()
0092             else:
0093                 raise Error("un(shallow)copyable object of type %s" % cls)
0094 
0095     return _reconstruct(x, rv, 0)
0096 
0097 
0098 _copy_dispatch = d = {}
0099 
0100 def _copy_immutable(x):
0101     return x
0102 for t in (types.NoneType, int, long, float, bool, str, tuple,
0103           frozenset, type, xrange, types.ClassType,
0104           types.BuiltinFunctionType):
0105     d[t] = _copy_immutable
0106 for name in ("ComplexType", "UnicodeType", "CodeType"):
0107     t = getattr(types, name, None)
0108     if t is not None:
0109         d[t] = _copy_immutable
0110 
0111 def _copy_with_constructor(x):
0112     return type(x)(x)
0113 for t in (list, dict, set):
0114     d[t] = _copy_with_constructor
0115 
0116 def _copy_with_copy_method(x):
0117     return x.copy()
0118 if PyStringMap is not None:
0119     d[PyStringMap] = _copy_with_copy_method
0120 
0121 def _copy_inst(x):
0122     if hasattr(x, '__copy__'):
0123         return x.__copy__()
0124     if hasattr(x, '__getinitargs__'):
0125         args = x.__getinitargs__()
0126         y = x.__class__(*args)
0127     else:
0128         y = _EmptyClass()
0129         y.__class__ = x.__class__
0130     if hasattr(x, '__getstate__'):
0131         state = x.__getstate__()
0132     else:
0133         state = x.__dict__
0134     if hasattr(y, '__setstate__'):
0135         y.__setstate__(state)
0136     else:
0137         y.__dict__.update(state)
0138     return y
0139 d[types.InstanceType] = _copy_inst
0140 
0141 del d
0142 
0143 def deepcopy(x, memo=None, _nil=[]):
0144     """Deep copy operation on arbitrary Python objects.
0145 
0146     See the module's __doc__ string for more info.
0147     """
0148 
0149     if memo is None:
0150         memo = {}
0151 
0152     d = id(x)
0153     y = memo.get(d, _nil)
0154     if y is not _nil:
0155         return y
0156 
0157     cls = type(x)
0158 
0159     copier = _deepcopy_dispatch.get(cls)
0160     if copier:
0161         y = copier(x, memo)
0162     else:
0163         try:
0164             issc = issubclass(cls, type)
0165         except TypeError: # cls is not a class (old Boost; see SF #502085)
0166             issc = 0
0167         if issc:
0168             y = _deepcopy_atomic(x, memo)
0169         else:
0170             copier = getattr(x, "__deepcopy__", None)
0171             if copier:
0172                 y = copier(memo)
0173             else:
0174                 reductor = dispatch_table.get(cls)
0175                 if reductor:
0176                     rv = reductor(x)
0177                 else:
0178                     reductor = getattr(x, "__reduce_ex__", None)
0179                     if reductor:
0180                         rv = reductor(2)
0181                     else:
0182                         reductor = getattr(x, "__reduce__", None)
0183                         if reductor:
0184                             rv = reductor()
0185                         else:
0186                             raise Error(
0187                                 "un(deep)copyable object of type %s" % cls)
0188                 y = _reconstruct(x, rv, 1, memo)
0189 
0190     memo[d] = y
0191     _keep_alive(x, memo) # Make sure x lives at least as long as d
0192     return y
0193 
0194 _deepcopy_dispatch = d = {}
0195 
0196 def _deepcopy_atomic(x, memo):
0197     return x
0198 d[types.NoneType] = _deepcopy_atomic
0199 d[types.IntType] = _deepcopy_atomic
0200 d[types.LongType] = _deepcopy_atomic
0201 d[types.FloatType] = _deepcopy_atomic
0202 d[types.BooleanType] = _deepcopy_atomic
0203 try:
0204     d[types.ComplexType] = _deepcopy_atomic
0205 except AttributeError:
0206     pass
0207 d[types.StringType] = _deepcopy_atomic
0208 try:
0209     d[types.UnicodeType] = _deepcopy_atomic
0210 except AttributeError:
0211     pass
0212 try:
0213     d[types.CodeType] = _deepcopy_atomic
0214 except AttributeError:
0215     pass
0216 d[types.TypeType] = _deepcopy_atomic
0217 d[types.XRangeType] = _deepcopy_atomic
0218 d[types.ClassType] = _deepcopy_atomic
0219 d[types.BuiltinFunctionType] = _deepcopy_atomic
0220 
0221 def _deepcopy_list(x, memo):
0222     y = []
0223     memo[id(x)] = y
0224     for a in x:
0225         y.append(deepcopy(a, memo))
0226     return y
0227 d[types.ListType] = _deepcopy_list
0228 
0229 def _deepcopy_tuple(x, memo):
0230     y = []
0231     for a in x:
0232         y.append(deepcopy(a, memo))
0233     d = id(x)
0234     try:
0235         return memo[d]
0236     except KeyError:
0237         pass
0238     for i in range(len(x)):
0239         if x[i] is not y[i]:
0240             y = tuple(y)
0241             break
0242     else:
0243         y = x
0244     memo[d] = y
0245     return y
0246 d[types.TupleType] = _deepcopy_tuple
0247 
0248 def _deepcopy_dict(x, memo):
0249     y = {}
0250     memo[id(x)] = y
0251     for key, value in x.iteritems():
0252         y[deepcopy(key, memo)] = deepcopy(value, memo)
0253     return y
0254 d[types.DictionaryType] = _deepcopy_dict
0255 if PyStringMap is not None:
0256     d[PyStringMap] = _deepcopy_dict
0257 
0258 def _keep_alive(x, memo):
0259     """Keeps a reference to the object x in the memo.
0260 
0261     Because we remember objects by their id, we have
0262     to assure that possibly temporary objects are kept
0263     alive by referencing them.
0264     We store a reference at the id of the memo, which should
0265     normally not be used unless someone tries to deepcopy
0266     the memo itself...
0267     """
0268     try:
0269         memo[id(memo)].append(x)
0270     except KeyError:
0271         # aha, this is the first one :-)
0272         memo[id(memo)]=[x]
0273 
0274 def _deepcopy_inst(x, memo):
0275     if hasattr(x, '__deepcopy__'):
0276         return x.__deepcopy__(memo)
0277     if hasattr(x, '__getinitargs__'):
0278         args = x.__getinitargs__()
0279         args = deepcopy(args, memo)
0280         y = x.__class__(*args)
0281     else:
0282         y = _EmptyClass()
0283         y.__class__ = x.__class__
0284     memo[id(x)] = y
0285     if hasattr(x, '__getstate__'):
0286         state = x.__getstate__()
0287     else:
0288         state = x.__dict__
0289     state = deepcopy(state, memo)
0290     if hasattr(y, '__setstate__'):
0291         y.__setstate__(state)
0292     else:
0293         y.__dict__.update(state)
0294     return y
0295 d[types.InstanceType] = _deepcopy_inst
0296 
0297 def _reconstruct(x, info, deep, memo=None):
0298     if isinstance(info, str):
0299         return x
0300     assert isinstance(info, tuple)
0301     if memo is None:
0302         memo = {}
0303     n = len(info)
0304     assert n in (2, 3, 4, 5)
0305     callable, args = info[:2]
0306     if n > 2:
0307         state = info[2]
0308     else:
0309         state = {}
0310     if n > 3:
0311         listiter = info[3]
0312     else:
0313         listiter = None
0314     if n > 4:
0315         dictiter = info[4]
0316     else:
0317         dictiter = None
0318     if deep:
0319         args = deepcopy(args, memo)
0320     y = callable(*args)
0321     memo[id(x)] = y
0322     if listiter is not None:
0323         for item in listiter:
0324             if deep:
0325                 item = deepcopy(item, memo)
0326             y.append(item)
0327     if dictiter is not None:
0328         for key, value in dictiter:
0329             if deep:
0330                 key = deepcopy(key, memo)
0331                 value = deepcopy(value, memo)
0332             y[key] = value
0333     if state:
0334         if deep:
0335             state = deepcopy(state, memo)
0336         if hasattr(y, '__setstate__'):
0337             y.__setstate__(state)
0338         else:
0339             if isinstance(state, tuple) and len(state) == 2:
0340                 state, slotstate = state
0341             else:
0342                 slotstate = None
0343             if state is not None:
0344                 y.__dict__.update(state)
0345             if slotstate is not None:
0346                 for key, value in slotstate.iteritems():
0347                     setattr(y, key, value)
0348     return y
0349 
0350 del d
0351 
0352 del types
0353 
0354 # Helper for instance creation without calling __init__
0355 class _EmptyClass:
0356     pass
0357 
0358 def _test():
0359     l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
0360          {'abc': 'ABC'}, (), [], {}]
0361     l1 = copy(l)
0362     print l1==l
0363     l1 = map(copy, l)
0364     print l1==l
0365     l1 = deepcopy(l)
0366     print l1==l
0367     class C:
0368         def __init__(self, arg=None):
0369             self.a = 1
0370             self.arg = arg
0371             if __name__ == '__main__':
0372                 import sys
0373                 file = sys.argv[0]
0374             else:
0375                 file = __file__
0376             self.fp = open(file)
0377             self.fp.close()
0378         def __getstate__(self):
0379             return {'a': self.a, 'arg': self.arg}
0380         def __setstate__(self, state):
0381             for key, value in state.iteritems():
0382                 setattr(self, key, value)
0383         def __deepcopy__(self, memo=None):
0384             new = self.__class__(deepcopy(self.arg, memo))
0385             new.a = self.a
0386             return new
0387     c = C('argument sketch')
0388     l.append(c)
0389     l2 = copy(l)
0390     print l == l2
0391     print l
0392     print l2
0393     l2 = deepcopy(l)
0394     print l == l2
0395     print l
0396     print l2
0397     l.append({l[1]: l, 'xyz': l[2]})
0398     l3 = copy(l)
0399     import repr
0400     print map(repr.repr, l)
0401     print map(repr.repr, l1)
0402     print map(repr.repr, l2)
0403     print map(repr.repr, l3)
0404     l3 = deepcopy(l)
0405     import repr
0406     print map(repr.repr, l)
0407     print map(repr.repr, l1)
0408     print map(repr.repr, l2)
0409     print map(repr.repr, l3)
0410 
0411 if __name__ == '__main__':
0412     _test()
0413 

Generated by PyXR 0.9.4
SourceForge.net Logo