github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/copy.py (about) 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 from '__go__/grumpy' import WeakRefType 52 import types 53 #from copy_reg import dispatch_table 54 import copy_reg 55 dispatch_table = copy_reg.dispatch_table 56 # Import directly from grumpy to avoid circular imports with weakref module. 57 58 class Error(Exception): 59 pass 60 error = Error # backward compatibility 61 62 #try: 63 # from org.python.core import PyStringMap 64 #except ImportError: 65 PyStringMap = None 66 67 __all__ = ["Error", "copy", "deepcopy"] 68 69 def copy(x): 70 """Shallow copy operation on arbitrary Python objects. 71 72 See the module's __doc__ string for more info. 73 """ 74 75 cls = type(x) 76 77 copier = _copy_dispatch.get(cls) 78 if copier: 79 return copier(x) 80 81 copier = getattr(cls, "__copy__", None) 82 if copier: 83 return copier(x) 84 85 reductor = dispatch_table.get(cls) 86 if reductor: 87 rv = reductor(x) 88 else: 89 reductor = getattr(x, "__reduce_ex__", None) 90 if reductor: 91 rv = reductor(2) 92 else: 93 reductor = getattr(x, "__reduce__", None) 94 if reductor: 95 rv = reductor() 96 else: 97 raise Error("un(shallow)copyable object of type %s" % cls) 98 99 return _reconstruct(x, rv, 0) 100 101 102 _copy_dispatch = d = {} 103 104 def _copy_immutable(x): 105 return x 106 for t in (type(None), int, float, bool, str, tuple, long, 107 type, xrange, frozenset, #types.ClassType 108 types.BuiltinFunctionType, # type(Ellipsis), 109 types.FunctionType, WeakRefType): 110 d[t] = _copy_immutable 111 for name in ("ComplexType", "UnicodeType", "CodeType"): 112 t = getattr(types, name, None) 113 if t is not None: 114 d[t] = _copy_immutable 115 116 def _copy_with_constructor(x): 117 return type(x)(x) 118 for t in (list, dict): # , set 119 d[t] = _copy_with_constructor 120 121 def _copy_with_copy_method(x): 122 return x.copy() 123 if PyStringMap is not None: 124 d[PyStringMap] = _copy_with_copy_method 125 126 #def _copy_inst(x): 127 # if hasattr(x, '__copy__'): 128 # return x.__copy__() 129 # if hasattr(x, '__getinitargs__'): 130 # args = x.__getinitargs__() 131 # y = x.__class__(*args) 132 # else: 133 # y = _EmptyClass() 134 # y.__class__ = x.__class__ 135 # if hasattr(x, '__getstate__'): 136 # state = x.__getstate__() 137 # else: 138 # state = x.__dict__ 139 # if hasattr(y, '__setstate__'): 140 # y.__setstate__(state) 141 # else: 142 # y.__dict__.update(state) 143 # return y 144 #d[types.InstanceType] = _copy_inst 145 146 del d 147 148 def deepcopy(x, memo=None, _nil=[]): 149 """Deep copy operation on arbitrary Python objects. 150 151 See the module's __doc__ string for more info. 152 """ 153 154 if memo is None: 155 memo = {} 156 157 d = id(x) 158 y = memo.get(d, _nil) 159 if y is not _nil: 160 return y 161 162 cls = type(x) 163 164 copier = _deepcopy_dispatch.get(cls) 165 if copier: 166 y = copier(x, memo) 167 else: 168 try: 169 issc = issubclass(cls, type) 170 except TypeError: # cls is not a class (old Boost; see SF #502085) 171 issc = 0 172 if issc: 173 y = _deepcopy_atomic(x, memo) 174 else: 175 copier = getattr(x, "__deepcopy__", None) 176 if copier: 177 y = copier(memo) 178 else: 179 reductor = dispatch_table.get(cls) 180 if reductor: 181 rv = reductor(x) 182 else: 183 reductor = getattr(x, "__reduce_ex__", None) 184 if reductor: 185 rv = reductor(2) 186 else: 187 reductor = getattr(x, "__reduce__", None) 188 if reductor: 189 rv = reductor() 190 else: 191 raise Error( 192 "un(deep)copyable object of type %s" % cls) 193 y = _reconstruct(x, rv, 1, memo) 194 195 memo[d] = y 196 _keep_alive(x, memo) # Make sure x lives at least as long as d 197 return y 198 199 _deepcopy_dispatch = d = {} 200 201 def _deepcopy_atomic(x, memo): 202 return x 203 d[type(None)] = _deepcopy_atomic 204 #d[type(Ellipsis)] = _deepcopy_atomic 205 d[int] = _deepcopy_atomic 206 d[long] = _deepcopy_atomic 207 d[float] = _deepcopy_atomic 208 d[bool] = _deepcopy_atomic 209 try: 210 d[complex] = _deepcopy_atomic 211 except NameError: 212 pass 213 d[str] = _deepcopy_atomic 214 try: 215 d[unicode] = _deepcopy_atomic 216 except NameError: 217 pass 218 try: 219 d[types.CodeType] = _deepcopy_atomic 220 except AttributeError: 221 pass 222 d[type] = _deepcopy_atomic 223 d[xrange] = _deepcopy_atomic 224 #d[types.ClassType] = _deepcopy_atomic 225 d[types.BuiltinFunctionType] = _deepcopy_atomic 226 d[types.FunctionType] = _deepcopy_atomic 227 d[WeakRefType] = _deepcopy_atomic 228 229 def _deepcopy_list(x, memo): 230 y = [] 231 memo[id(x)] = y 232 for a in x: 233 y.append(deepcopy(a, memo)) 234 return y 235 d[list] = _deepcopy_list 236 237 def _deepcopy_tuple(x, memo): 238 y = [] 239 for a in x: 240 y.append(deepcopy(a, memo)) 241 d = id(x) 242 try: 243 return memo[d] 244 except KeyError: 245 pass 246 for i in range(len(x)): 247 if x[i] is not y[i]: 248 y = tuple(y) 249 break 250 else: 251 y = x 252 memo[d] = y 253 return y 254 d[tuple] = _deepcopy_tuple 255 256 def _deepcopy_dict(x, memo): 257 y = {} 258 memo[id(x)] = y 259 for key, value in x.iteritems(): 260 y[deepcopy(key, memo)] = deepcopy(value, memo) 261 return y 262 d[dict] = _deepcopy_dict 263 if PyStringMap is not None: 264 d[PyStringMap] = _deepcopy_dict 265 266 def _deepcopy_method(x, memo): # Copy instance methods 267 return type(x)(x.im_func, deepcopy(x.im_self, memo), x.im_class) 268 _deepcopy_dispatch[types.MethodType] = _deepcopy_method 269 270 def _keep_alive(x, memo): 271 """Keeps a reference to the object x in the memo. 272 273 Because we remember objects by their id, we have 274 to assure that possibly temporary objects are kept 275 alive by referencing them. 276 We store a reference at the id of the memo, which should 277 normally not be used unless someone tries to deepcopy 278 the memo itself... 279 """ 280 try: 281 memo[id(memo)].append(x) 282 except KeyError: 283 # aha, this is the first one :-) 284 memo[id(memo)]=[x] 285 286 #def _deepcopy_inst(x, memo): 287 # if hasattr(x, '__deepcopy__'): 288 # return x.__deepcopy__(memo) 289 # if hasattr(x, '__getinitargs__'): 290 # args = x.__getinitargs__() 291 # args = deepcopy(args, memo) 292 # y = x.__class__(*args) 293 # else: 294 # y = _EmptyClass() 295 # y.__class__ = x.__class__ 296 # memo[id(x)] = y 297 # if hasattr(x, '__getstate__'): 298 # state = x.__getstate__() 299 # else: 300 # state = x.__dict__ 301 # state = deepcopy(state, memo) 302 # if hasattr(y, '__setstate__'): 303 # y.__setstate__(state) 304 # else: 305 # y.__dict__.update(state) 306 # return y 307 #d[types.InstanceType] = _deepcopy_inst 308 309 def _reconstruct(x, info, deep, memo=None): 310 if isinstance(info, str): 311 return x 312 assert isinstance(info, tuple) 313 if memo is None: 314 memo = {} 315 n = len(info) 316 assert n in (2, 3, 4, 5) 317 callable, args = info[:2] 318 if n > 2: 319 state = info[2] 320 else: 321 state = None 322 if n > 3: 323 listiter = info[3] 324 else: 325 listiter = None 326 if n > 4: 327 dictiter = info[4] 328 else: 329 dictiter = None 330 if deep: 331 args = deepcopy(args, memo) 332 y = callable(*args) 333 memo[id(x)] = y 334 335 if state is not None: 336 if deep: 337 state = deepcopy(state, memo) 338 if hasattr(y, '__setstate__'): 339 y.__setstate__(state) 340 else: 341 if isinstance(state, tuple) and len(state) == 2: 342 state, slotstate = state 343 else: 344 slotstate = None 345 if state is not None: 346 y.__dict__.update(state) 347 if slotstate is not None: 348 for key, value in slotstate.iteritems(): 349 setattr(y, key, value) 350 351 if listiter is not None: 352 for item in listiter: 353 if deep: 354 item = deepcopy(item, memo) 355 y.append(item) 356 if dictiter is not None: 357 for key, value in dictiter: 358 if deep: 359 key = deepcopy(key, memo) 360 value = deepcopy(value, memo) 361 y[key] = value 362 return y 363 364 del d 365 366 del types 367 368 # Helper for instance creation without calling __init__ 369 #class _EmptyClass: 370 # pass 371 372 def _test(): 373 #l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'], 374 l = [None, 1, 3.14, 'xyzzy', (1,), [3.14, 'abc'], 375 {'abc': 'ABC'}, (), [], {}] 376 l1 = copy(l) 377 print l1==l 378 l1 = map(copy, l) 379 print l1==l 380 l1 = deepcopy(l) 381 print l1==l 382 class C: 383 def __init__(self, arg=None): 384 self.a = 1 385 self.arg = arg 386 if __name__ == '__main__': 387 import sys 388 file = sys.argv[0] 389 else: 390 file = __file__ 391 self.fp = open(file) 392 self.fp.close() 393 def __getstate__(self): 394 return {'a': self.a, 'arg': self.arg} 395 def __setstate__(self, state): 396 for key, value in state.iteritems(): 397 setattr(self, key, value) 398 def __deepcopy__(self, memo=None): 399 new = self.__class__(deepcopy(self.arg, memo)) 400 new.a = self.a 401 return new 402 c = C('argument sketch') 403 l.append(c) 404 l2 = copy(l) 405 print l == l2 406 print l 407 print l2 408 l2 = deepcopy(l) 409 print l == l2 410 print l 411 print l2 412 l.append({l[1]: l, 'xyz': l[2]}) 413 l3 = copy(l) 414 import repr 415 print map(repr.repr, l) 416 print map(repr.repr, l1) 417 print map(repr.repr, l2) 418 print map(repr.repr, l3) 419 l3 = deepcopy(l) 420 import repr 421 print map(repr.repr, l) 422 print map(repr.repr, l1) 423 print map(repr.repr, l2) 424 print map(repr.repr, l3) 425 class odict(dict): 426 def __init__(self, d = {}): 427 self.a = 99 428 dict.__init__(self, d) 429 def __setitem__(self, k, i): 430 dict.__setitem__(self, k, i) 431 self.a 432 o = odict({"A" : "B"}) 433 x = deepcopy(o) 434 print(o, x) 435 436 if __name__ == '__main__': 437 _test()