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