Deep copy operation on arbitrary Python objects. See the module's __doc__ string for more info.
(x, memo=None)
| 108 | _copy_builtin_containers = frozenset({list, dict, set, bytearray}) |
| 109 | |
| 110 | def deepcopy(x, memo=None): |
| 111 | """Deep copy operation on arbitrary Python objects. |
| 112 | |
| 113 | See the module's __doc__ string for more info. |
| 114 | """ |
| 115 | |
| 116 | cls = type(x) |
| 117 | |
| 118 | if cls in _atomic_types: |
| 119 | return x |
| 120 | |
| 121 | d = id(x) |
| 122 | if memo is None: |
| 123 | memo = {} |
| 124 | else: |
| 125 | y = memo.get(d, None) |
| 126 | if y is not None: |
| 127 | return y |
| 128 | |
| 129 | copier = _deepcopy_dispatch.get(cls) |
| 130 | if copier is not None: |
| 131 | y = copier(x, memo) |
| 132 | else: |
| 133 | if issubclass(cls, type): |
| 134 | y = x # atomic copy |
| 135 | else: |
| 136 | copier = getattr(x, "__deepcopy__", None) |
| 137 | if copier is not None: |
| 138 | y = copier(memo) |
| 139 | else: |
| 140 | reductor = dispatch_table.get(cls) |
| 141 | if reductor: |
| 142 | rv = reductor(x) |
| 143 | else: |
| 144 | reductor = getattr(x, "__reduce_ex__", None) |
| 145 | if reductor is not None: |
| 146 | rv = reductor(4) |
| 147 | else: |
| 148 | reductor = getattr(x, "__reduce__", None) |
| 149 | if reductor: |
| 150 | rv = reductor() |
| 151 | else: |
| 152 | raise Error( |
| 153 | "un(deep)copyable object of type %s" % cls) |
| 154 | if isinstance(rv, str): |
| 155 | y = x |
| 156 | else: |
| 157 | y = _reconstruct(x, memo, *rv) |
| 158 | |
| 159 | # If is its own copy, don't memoize. |
| 160 | if y is not x: |
| 161 | memo[d] = y |
| 162 | _keep_alive(x, memo) # Make sure x lives at least as long as d |
| 163 | return y |
| 164 | |
| 165 | _atomic_types = frozenset({types.NoneType, types.EllipsisType, types.NotImplementedType, |
| 166 | int, float, bool, complex, bytes, str, types.CodeType, type, range, |
searching dependent graphs…