17db96d56Sopenharmony_ci"""Generic (shallow and deep) copying operations. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciInterface summary: 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci import copy 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ci x = copy.copy(y) # make a shallow copy of y 87db96d56Sopenharmony_ci x = copy.deepcopy(y) # make a deep copy of y 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciFor module specific errors, copy.Error is raised. 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciThe difference between shallow and deep copying is only relevant for 137db96d56Sopenharmony_cicompound objects (objects that contain other objects, like lists or 147db96d56Sopenharmony_ciclass instances). 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci- A shallow copy constructs a new compound object and then (to the 177db96d56Sopenharmony_ci extent possible) inserts *the same objects* into it that the 187db96d56Sopenharmony_ci original contains. 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci- A deep copy constructs a new compound object and then, recursively, 217db96d56Sopenharmony_ci inserts *copies* into it of the objects found in the original. 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ciTwo problems often exist with deep copy operations that don't exist 247db96d56Sopenharmony_ciwith shallow copy operations: 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci a) recursive objects (compound objects that, directly or indirectly, 277db96d56Sopenharmony_ci contain a reference to themselves) may cause a recursive loop 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci b) because deep copy copies *everything* it may copy too much, e.g. 307db96d56Sopenharmony_ci administrative data structures that should be shared even between 317db96d56Sopenharmony_ci copies 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ciPython's deep copy operation avoids these problems by: 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci a) keeping a table of objects already copied during the current 367db96d56Sopenharmony_ci copying pass 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ci b) letting user-defined classes override the copying operation or the 397db96d56Sopenharmony_ci set of components copied 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ciThis version does not copy types like module, class, function, method, 427db96d56Sopenharmony_cinor stack trace, stack frame, nor file, socket, window, nor any 437db96d56Sopenharmony_cisimilar types. 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ciClasses can use the same interfaces to control copying that they use 467db96d56Sopenharmony_cito control pickling: they can define methods called __getinitargs__(), 477db96d56Sopenharmony_ci__getstate__() and __setstate__(). See the documentation for module 487db96d56Sopenharmony_ci"pickle" for information on these methods. 497db96d56Sopenharmony_ci""" 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ciimport types 527db96d56Sopenharmony_ciimport weakref 537db96d56Sopenharmony_cifrom copyreg import dispatch_table 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciclass Error(Exception): 567db96d56Sopenharmony_ci pass 577db96d56Sopenharmony_cierror = Error # backward compatibility 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_citry: 607db96d56Sopenharmony_ci from org.python.core import PyStringMap 617db96d56Sopenharmony_ciexcept ImportError: 627db96d56Sopenharmony_ci PyStringMap = None 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci__all__ = ["Error", "copy", "deepcopy"] 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_cidef copy(x): 677db96d56Sopenharmony_ci """Shallow copy operation on arbitrary Python objects. 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci See the module's __doc__ string for more info. 707db96d56Sopenharmony_ci """ 717db96d56Sopenharmony_ci 727db96d56Sopenharmony_ci cls = type(x) 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci copier = _copy_dispatch.get(cls) 757db96d56Sopenharmony_ci if copier: 767db96d56Sopenharmony_ci return copier(x) 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci if issubclass(cls, type): 797db96d56Sopenharmony_ci # treat it as a regular class: 807db96d56Sopenharmony_ci return _copy_immutable(x) 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci copier = getattr(cls, "__copy__", None) 837db96d56Sopenharmony_ci if copier is not None: 847db96d56Sopenharmony_ci return copier(x) 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci reductor = dispatch_table.get(cls) 877db96d56Sopenharmony_ci if reductor is not None: 887db96d56Sopenharmony_ci rv = reductor(x) 897db96d56Sopenharmony_ci else: 907db96d56Sopenharmony_ci reductor = getattr(x, "__reduce_ex__", None) 917db96d56Sopenharmony_ci if reductor is not None: 927db96d56Sopenharmony_ci rv = reductor(4) 937db96d56Sopenharmony_ci else: 947db96d56Sopenharmony_ci reductor = getattr(x, "__reduce__", None) 957db96d56Sopenharmony_ci if reductor: 967db96d56Sopenharmony_ci rv = reductor() 977db96d56Sopenharmony_ci else: 987db96d56Sopenharmony_ci raise Error("un(shallow)copyable object of type %s" % cls) 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci if isinstance(rv, str): 1017db96d56Sopenharmony_ci return x 1027db96d56Sopenharmony_ci return _reconstruct(x, None, *rv) 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci_copy_dispatch = d = {} 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_cidef _copy_immutable(x): 1087db96d56Sopenharmony_ci return x 1097db96d56Sopenharmony_cifor t in (type(None), int, float, bool, complex, str, tuple, 1107db96d56Sopenharmony_ci bytes, frozenset, type, range, slice, property, 1117db96d56Sopenharmony_ci types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented), 1127db96d56Sopenharmony_ci types.FunctionType, weakref.ref): 1137db96d56Sopenharmony_ci d[t] = _copy_immutable 1147db96d56Sopenharmony_cit = getattr(types, "CodeType", None) 1157db96d56Sopenharmony_ciif t is not None: 1167db96d56Sopenharmony_ci d[t] = _copy_immutable 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_cid[list] = list.copy 1197db96d56Sopenharmony_cid[dict] = dict.copy 1207db96d56Sopenharmony_cid[set] = set.copy 1217db96d56Sopenharmony_cid[bytearray] = bytearray.copy 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ciif PyStringMap is not None: 1247db96d56Sopenharmony_ci d[PyStringMap] = PyStringMap.copy 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_cidel d, t 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_cidef deepcopy(x, memo=None, _nil=[]): 1297db96d56Sopenharmony_ci """Deep copy operation on arbitrary Python objects. 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci See the module's __doc__ string for more info. 1327db96d56Sopenharmony_ci """ 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ci if memo is None: 1357db96d56Sopenharmony_ci memo = {} 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci d = id(x) 1387db96d56Sopenharmony_ci y = memo.get(d, _nil) 1397db96d56Sopenharmony_ci if y is not _nil: 1407db96d56Sopenharmony_ci return y 1417db96d56Sopenharmony_ci 1427db96d56Sopenharmony_ci cls = type(x) 1437db96d56Sopenharmony_ci 1447db96d56Sopenharmony_ci copier = _deepcopy_dispatch.get(cls) 1457db96d56Sopenharmony_ci if copier is not None: 1467db96d56Sopenharmony_ci y = copier(x, memo) 1477db96d56Sopenharmony_ci else: 1487db96d56Sopenharmony_ci if issubclass(cls, type): 1497db96d56Sopenharmony_ci y = _deepcopy_atomic(x, memo) 1507db96d56Sopenharmony_ci else: 1517db96d56Sopenharmony_ci copier = getattr(x, "__deepcopy__", None) 1527db96d56Sopenharmony_ci if copier is not None: 1537db96d56Sopenharmony_ci y = copier(memo) 1547db96d56Sopenharmony_ci else: 1557db96d56Sopenharmony_ci reductor = dispatch_table.get(cls) 1567db96d56Sopenharmony_ci if reductor: 1577db96d56Sopenharmony_ci rv = reductor(x) 1587db96d56Sopenharmony_ci else: 1597db96d56Sopenharmony_ci reductor = getattr(x, "__reduce_ex__", None) 1607db96d56Sopenharmony_ci if reductor is not None: 1617db96d56Sopenharmony_ci rv = reductor(4) 1627db96d56Sopenharmony_ci else: 1637db96d56Sopenharmony_ci reductor = getattr(x, "__reduce__", None) 1647db96d56Sopenharmony_ci if reductor: 1657db96d56Sopenharmony_ci rv = reductor() 1667db96d56Sopenharmony_ci else: 1677db96d56Sopenharmony_ci raise Error( 1687db96d56Sopenharmony_ci "un(deep)copyable object of type %s" % cls) 1697db96d56Sopenharmony_ci if isinstance(rv, str): 1707db96d56Sopenharmony_ci y = x 1717db96d56Sopenharmony_ci else: 1727db96d56Sopenharmony_ci y = _reconstruct(x, memo, *rv) 1737db96d56Sopenharmony_ci 1747db96d56Sopenharmony_ci # If is its own copy, don't memoize. 1757db96d56Sopenharmony_ci if y is not x: 1767db96d56Sopenharmony_ci memo[d] = y 1777db96d56Sopenharmony_ci _keep_alive(x, memo) # Make sure x lives at least as long as d 1787db96d56Sopenharmony_ci return y 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci_deepcopy_dispatch = d = {} 1817db96d56Sopenharmony_ci 1827db96d56Sopenharmony_cidef _deepcopy_atomic(x, memo): 1837db96d56Sopenharmony_ci return x 1847db96d56Sopenharmony_cid[type(None)] = _deepcopy_atomic 1857db96d56Sopenharmony_cid[type(Ellipsis)] = _deepcopy_atomic 1867db96d56Sopenharmony_cid[type(NotImplemented)] = _deepcopy_atomic 1877db96d56Sopenharmony_cid[int] = _deepcopy_atomic 1887db96d56Sopenharmony_cid[float] = _deepcopy_atomic 1897db96d56Sopenharmony_cid[bool] = _deepcopy_atomic 1907db96d56Sopenharmony_cid[complex] = _deepcopy_atomic 1917db96d56Sopenharmony_cid[bytes] = _deepcopy_atomic 1927db96d56Sopenharmony_cid[str] = _deepcopy_atomic 1937db96d56Sopenharmony_cid[types.CodeType] = _deepcopy_atomic 1947db96d56Sopenharmony_cid[type] = _deepcopy_atomic 1957db96d56Sopenharmony_cid[range] = _deepcopy_atomic 1967db96d56Sopenharmony_cid[types.BuiltinFunctionType] = _deepcopy_atomic 1977db96d56Sopenharmony_cid[types.FunctionType] = _deepcopy_atomic 1987db96d56Sopenharmony_cid[weakref.ref] = _deepcopy_atomic 1997db96d56Sopenharmony_cid[property] = _deepcopy_atomic 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_cidef _deepcopy_list(x, memo, deepcopy=deepcopy): 2027db96d56Sopenharmony_ci y = [] 2037db96d56Sopenharmony_ci memo[id(x)] = y 2047db96d56Sopenharmony_ci append = y.append 2057db96d56Sopenharmony_ci for a in x: 2067db96d56Sopenharmony_ci append(deepcopy(a, memo)) 2077db96d56Sopenharmony_ci return y 2087db96d56Sopenharmony_cid[list] = _deepcopy_list 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_cidef _deepcopy_tuple(x, memo, deepcopy=deepcopy): 2117db96d56Sopenharmony_ci y = [deepcopy(a, memo) for a in x] 2127db96d56Sopenharmony_ci # We're not going to put the tuple in the memo, but it's still important we 2137db96d56Sopenharmony_ci # check for it, in case the tuple contains recursive mutable structures. 2147db96d56Sopenharmony_ci try: 2157db96d56Sopenharmony_ci return memo[id(x)] 2167db96d56Sopenharmony_ci except KeyError: 2177db96d56Sopenharmony_ci pass 2187db96d56Sopenharmony_ci for k, j in zip(x, y): 2197db96d56Sopenharmony_ci if k is not j: 2207db96d56Sopenharmony_ci y = tuple(y) 2217db96d56Sopenharmony_ci break 2227db96d56Sopenharmony_ci else: 2237db96d56Sopenharmony_ci y = x 2247db96d56Sopenharmony_ci return y 2257db96d56Sopenharmony_cid[tuple] = _deepcopy_tuple 2267db96d56Sopenharmony_ci 2277db96d56Sopenharmony_cidef _deepcopy_dict(x, memo, deepcopy=deepcopy): 2287db96d56Sopenharmony_ci y = {} 2297db96d56Sopenharmony_ci memo[id(x)] = y 2307db96d56Sopenharmony_ci for key, value in x.items(): 2317db96d56Sopenharmony_ci y[deepcopy(key, memo)] = deepcopy(value, memo) 2327db96d56Sopenharmony_ci return y 2337db96d56Sopenharmony_cid[dict] = _deepcopy_dict 2347db96d56Sopenharmony_ciif PyStringMap is not None: 2357db96d56Sopenharmony_ci d[PyStringMap] = _deepcopy_dict 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_cidef _deepcopy_method(x, memo): # Copy instance methods 2387db96d56Sopenharmony_ci return type(x)(x.__func__, deepcopy(x.__self__, memo)) 2397db96d56Sopenharmony_cid[types.MethodType] = _deepcopy_method 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_cidel d 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_cidef _keep_alive(x, memo): 2447db96d56Sopenharmony_ci """Keeps a reference to the object x in the memo. 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci Because we remember objects by their id, we have 2477db96d56Sopenharmony_ci to assure that possibly temporary objects are kept 2487db96d56Sopenharmony_ci alive by referencing them. 2497db96d56Sopenharmony_ci We store a reference at the id of the memo, which should 2507db96d56Sopenharmony_ci normally not be used unless someone tries to deepcopy 2517db96d56Sopenharmony_ci the memo itself... 2527db96d56Sopenharmony_ci """ 2537db96d56Sopenharmony_ci try: 2547db96d56Sopenharmony_ci memo[id(memo)].append(x) 2557db96d56Sopenharmony_ci except KeyError: 2567db96d56Sopenharmony_ci # aha, this is the first one :-) 2577db96d56Sopenharmony_ci memo[id(memo)]=[x] 2587db96d56Sopenharmony_ci 2597db96d56Sopenharmony_cidef _reconstruct(x, memo, func, args, 2607db96d56Sopenharmony_ci state=None, listiter=None, dictiter=None, 2617db96d56Sopenharmony_ci *, deepcopy=deepcopy): 2627db96d56Sopenharmony_ci deep = memo is not None 2637db96d56Sopenharmony_ci if deep and args: 2647db96d56Sopenharmony_ci args = (deepcopy(arg, memo) for arg in args) 2657db96d56Sopenharmony_ci y = func(*args) 2667db96d56Sopenharmony_ci if deep: 2677db96d56Sopenharmony_ci memo[id(x)] = y 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_ci if state is not None: 2707db96d56Sopenharmony_ci if deep: 2717db96d56Sopenharmony_ci state = deepcopy(state, memo) 2727db96d56Sopenharmony_ci if hasattr(y, '__setstate__'): 2737db96d56Sopenharmony_ci y.__setstate__(state) 2747db96d56Sopenharmony_ci else: 2757db96d56Sopenharmony_ci if isinstance(state, tuple) and len(state) == 2: 2767db96d56Sopenharmony_ci state, slotstate = state 2777db96d56Sopenharmony_ci else: 2787db96d56Sopenharmony_ci slotstate = None 2797db96d56Sopenharmony_ci if state is not None: 2807db96d56Sopenharmony_ci y.__dict__.update(state) 2817db96d56Sopenharmony_ci if slotstate is not None: 2827db96d56Sopenharmony_ci for key, value in slotstate.items(): 2837db96d56Sopenharmony_ci setattr(y, key, value) 2847db96d56Sopenharmony_ci 2857db96d56Sopenharmony_ci if listiter is not None: 2867db96d56Sopenharmony_ci if deep: 2877db96d56Sopenharmony_ci for item in listiter: 2887db96d56Sopenharmony_ci item = deepcopy(item, memo) 2897db96d56Sopenharmony_ci y.append(item) 2907db96d56Sopenharmony_ci else: 2917db96d56Sopenharmony_ci for item in listiter: 2927db96d56Sopenharmony_ci y.append(item) 2937db96d56Sopenharmony_ci if dictiter is not None: 2947db96d56Sopenharmony_ci if deep: 2957db96d56Sopenharmony_ci for key, value in dictiter: 2967db96d56Sopenharmony_ci key = deepcopy(key, memo) 2977db96d56Sopenharmony_ci value = deepcopy(value, memo) 2987db96d56Sopenharmony_ci y[key] = value 2997db96d56Sopenharmony_ci else: 3007db96d56Sopenharmony_ci for key, value in dictiter: 3017db96d56Sopenharmony_ci y[key] = value 3027db96d56Sopenharmony_ci return y 3037db96d56Sopenharmony_ci 3047db96d56Sopenharmony_cidel types, weakref, PyStringMap 305