copy.py 9.81 KB
Newer Older
1
"""Generic (shallow and deep) copying operations.
2

3 4
Interface summary:

Tim Peters's avatar
Tim Peters committed
5
        import copy
6

Tim Peters's avatar
Tim Peters committed
7 8
        x = copy.copy(y)        # make a shallow copy of y
        x = copy.deepcopy(y)    # make a deep copy of y
9

10
For module specific errors, copy.Error is raised.
11 12 13 14 15 16

The difference between shallow and deep copying is only relevant for
compound objects (objects that contain other objects, like lists or
class instances).

- A shallow copy constructs a new compound object and then (to the
17
  extent possible) inserts *the same objects* into it that the
18 19 20 21 22 23 24 25
  original contains.

- A deep copy constructs a new compound object and then, recursively,
  inserts *copies* into it of the objects found in the original.

Two problems often exist with deep copy operations that don't exist
with shallow copy operations:

26
 a) recursive objects (compound objects that, directly or indirectly,
27 28
    contain a reference to themselves) may cause a recursive loop

29
 b) because deep copy copies *everything* it may copy too much, e.g.
30 31 32 33 34
    administrative data structures that should be shared even between
    copies

Python's deep copy operation avoids these problems by:

35 36
 a) keeping a table of objects already copied during the current
    copying pass
37

38
 b) letting user-defined classes override the copying operation or the
39 40 41 42 43 44 45 46
    set of components copied

This version does not copy types like module, class, function, method,
nor stack trace, stack frame, nor file, socket, window, nor array, nor
any similar types.

Classes can use the same interfaces to control copying that they use
to control pickling: they can define methods called __getinitargs__(),
47
__getstate__() and __setstate__().  See the documentation for module
48 49
"pickle" for information on these methods.
"""
50 51

import types
52
import weakref
53
from copyreg import dispatch_table
54

55
class Error(Exception):
Tim Peters's avatar
Tim Peters committed
56 57
    pass
error = Error   # backward compatibility
58

59 60 61 62 63
try:
    from org.python.core import PyStringMap
except ImportError:
    PyStringMap = None

64
__all__ = ["Error", "copy", "deepcopy"]
65

66
def copy(x):
Tim Peters's avatar
Tim Peters committed
67 68 69 70 71
    """Shallow copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.
    """

72 73 74 75 76 77 78 79 80 81 82
    cls = type(x)

    copier = _copy_dispatch.get(cls)
    if copier:
        return copier(x)

    copier = getattr(cls, "__copy__", None)
    if copier:
        return copier(x)

    reductor = dispatch_table.get(cls)
83 84 85 86 87 88 89 90 91 92 93 94 95 96
    if reductor:
        rv = reductor(x)
    else:
        reductor = getattr(x, "__reduce_ex__", None)
        if reductor:
            rv = reductor(2)
        else:
            reductor = getattr(x, "__reduce__", None)
            if reductor:
                rv = reductor()
            else:
                raise Error("un(shallow)copyable object of type %s" % cls)

    return _reconstruct(x, rv, 0)
Tim Peters's avatar
Tim Peters committed
97

98

99 100
_copy_dispatch = d = {}

101
def _copy_immutable(x):
Tim Peters's avatar
Tim Peters committed
102
    return x
103
for t in (type(None), int, float, bool, str, tuple,
104
          frozenset, type, range,
Christian Heimes's avatar
Christian Heimes committed
105
          types.BuiltinFunctionType, type(Ellipsis),
106
          types.FunctionType, weakref.ref):
107
    d[t] = _copy_immutable
108 109 110 111 112
t = getattr(types, "CodeType", None)
if t is not None:
    d[t] = _copy_immutable
for name in ("complex", "unicode"):
    t = globals()['__builtins__'].get(name)
113 114 115 116 117 118 119 120 121
    if t is not None:
        d[t] = _copy_immutable

def _copy_with_constructor(x):
    return type(x)(x)
for t in (list, dict, set):
    d[t] = _copy_with_constructor

def _copy_with_copy_method(x):
Tim Peters's avatar
Tim Peters committed
122
    return x.copy()
123
if PyStringMap is not None:
124
    d[PyStringMap] = _copy_with_copy_method
125 126 127

del d

128
def deepcopy(x, memo=None, _nil=[]):
Tim Peters's avatar
Tim Peters committed
129 130 131 132 133 134 135
    """Deep copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.
    """

    if memo is None:
        memo = {}
136

Tim Peters's avatar
Tim Peters committed
137
    d = id(x)
138 139 140 141 142 143 144 145 146 147
    y = memo.get(d, _nil)
    if y is not _nil:
        return y

    cls = type(x)

    copier = _deepcopy_dispatch.get(cls)
    if copier:
        y = copier(x, memo)
    else:
Tim Peters's avatar
Tim Peters committed
148
        try:
149 150
            issc = issubclass(cls, type)
        except TypeError: # cls is not a class (old Boost; see SF #502085)
151 152
            issc = 0
        if issc:
153
            y = _deepcopy_atomic(x, memo)
154
        else:
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
            copier = getattr(x, "__deepcopy__", None)
            if copier:
                y = copier(memo)
            else:
                reductor = dispatch_table.get(cls)
                if reductor:
                    rv = reductor(x)
                else:
                    reductor = getattr(x, "__reduce_ex__", None)
                    if reductor:
                        rv = reductor(2)
                    else:
                        reductor = getattr(x, "__reduce__", None)
                        if reductor:
                            rv = reductor()
                        else:
                            raise Error(
                                "un(deep)copyable object of type %s" % cls)
                y = _reconstruct(x, rv, 1, memo)
174

Tim Peters's avatar
Tim Peters committed
175
    memo[d] = y
176
    _keep_alive(x, memo) # Make sure x lives at least as long as d
Tim Peters's avatar
Tim Peters committed
177
    return y
178 179 180 181

_deepcopy_dispatch = d = {}

def _deepcopy_atomic(x, memo):
Tim Peters's avatar
Tim Peters committed
182
    return x
183
d[type(None)] = _deepcopy_atomic
Christian Heimes's avatar
Christian Heimes committed
184
d[type(Ellipsis)] = _deepcopy_atomic
185 186 187
d[int] = _deepcopy_atomic
d[float] = _deepcopy_atomic
d[bool] = _deepcopy_atomic
188
try:
189
    d[complex] = _deepcopy_atomic
190
except NameError:
191
    pass
192
d[bytes] = _deepcopy_atomic
193
d[str] = _deepcopy_atomic
194 195 196 197
try:
    d[types.CodeType] = _deepcopy_atomic
except AttributeError:
    pass
198
d[type] = _deepcopy_atomic
199
d[range] = _deepcopy_atomic
200
d[types.BuiltinFunctionType] = _deepcopy_atomic
Guido van Rossum's avatar
Guido van Rossum committed
201
d[types.FunctionType] = _deepcopy_atomic
202
d[weakref.ref] = _deepcopy_atomic
203 204

def _deepcopy_list(x, memo):
Tim Peters's avatar
Tim Peters committed
205 206 207 208 209
    y = []
    memo[id(x)] = y
    for a in x:
        y.append(deepcopy(a, memo))
    return y
210
d[list] = _deepcopy_list
211 212

def _deepcopy_tuple(x, memo):
Tim Peters's avatar
Tim Peters committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    y = []
    for a in x:
        y.append(deepcopy(a, memo))
    d = id(x)
    try:
        return memo[d]
    except KeyError:
        pass
    for i in range(len(x)):
        if x[i] is not y[i]:
            y = tuple(y)
            break
    else:
        y = x
    memo[d] = y
    return y
229
d[tuple] = _deepcopy_tuple
230 231

def _deepcopy_dict(x, memo):
Tim Peters's avatar
Tim Peters committed
232 233
    y = {}
    memo[id(x)] = y
234
    for key, value in x.items():
235
        y[deepcopy(key, memo)] = deepcopy(value, memo)
Tim Peters's avatar
Tim Peters committed
236
    return y
237
d[dict] = _deepcopy_dict
238 239
if PyStringMap is not None:
    d[PyStringMap] = _deepcopy_dict
240

241 242 243 244
def _deepcopy_method(x, memo): # Copy instance methods
    return type(x)(x.__func__, deepcopy(x.__self__, memo))
_deepcopy_dispatch[types.MethodType] = _deepcopy_method

245
def _keep_alive(x, memo):
Tim Peters's avatar
Tim Peters committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259
    """Keeps a reference to the object x in the memo.

    Because we remember objects by their id, we have
    to assure that possibly temporary objects are kept
    alive by referencing them.
    We store a reference at the id of the memo, which should
    normally not be used unless someone tries to deepcopy
    the memo itself...
    """
    try:
        memo[id(memo)].append(x)
    except KeyError:
        # aha, this is the first one :-)
        memo[id(memo)]=[x]
260

261
def _reconstruct(x, info, deep, memo=None):
262 263 264
    if isinstance(info, str):
        return x
    assert isinstance(info, tuple)
265 266
    if memo is None:
        memo = {}
267
    n = len(info)
268
    assert n in (2, 3, 4, 5)
269 270 271 272 273
    callable, args = info[:2]
    if n > 2:
        state = info[2]
    else:
        state = {}
274 275 276 277 278 279 280 281
    if n > 3:
        listiter = info[3]
    else:
        listiter = None
    if n > 4:
        dictiter = info[4]
    else:
        dictiter = None
282
    if deep:
283
        args = deepcopy(args, memo)
284
    y = callable(*args)
285
    memo[id(x)] = y
286 287 288 289 290 291 292 293 294 295 296
    if listiter is not None:
        for item in listiter:
            if deep:
                item = deepcopy(item, memo)
            y.append(item)
    if dictiter is not None:
        for key, value in dictiter:
            if deep:
                key = deepcopy(key, memo)
                value = deepcopy(value, memo)
            y[key] = value
297 298
    if state:
        if deep:
299
            state = deepcopy(state, memo)
300 301 302
        if hasattr(y, '__setstate__'):
            y.__setstate__(state)
        else:
303 304 305 306 307 308 309
            if isinstance(state, tuple) and len(state) == 2:
                state, slotstate = state
            else:
                slotstate = None
            if state is not None:
                y.__dict__.update(state)
            if slotstate is not None:
310
                for key, value in slotstate.items():
311
                    setattr(y, key, value)
312 313
    return y

314 315 316 317
del d

del types

318 319 320 321
# Helper for instance creation without calling __init__
class _EmptyClass:
    pass

322
def _test():
323
    l = [None, 1, 2, 3.14, 'xyzzy', (1, 2), [3.14, 'abc'],
Tim Peters's avatar
Tim Peters committed
324 325
         {'abc': 'ABC'}, (), [], {}]
    l1 = copy(l)
326
    print(l1==l)
Tim Peters's avatar
Tim Peters committed
327
    l1 = map(copy, l)
328
    print(l1==l)
Tim Peters's avatar
Tim Peters committed
329
    l1 = deepcopy(l)
330
    print(l1==l)
Tim Peters's avatar
Tim Peters committed
331 332 333 334 335 336 337 338 339 340 341 342 343 344
    class C:
        def __init__(self, arg=None):
            self.a = 1
            self.arg = arg
            if __name__ == '__main__':
                import sys
                file = sys.argv[0]
            else:
                file = __file__
            self.fp = open(file)
            self.fp.close()
        def __getstate__(self):
            return {'a': self.a, 'arg': self.arg}
        def __setstate__(self, state):
345
            for key, value in state.items():
346
                setattr(self, key, value)
347
        def __deepcopy__(self, memo=None):
Tim Peters's avatar
Tim Peters committed
348 349 350 351 352 353
            new = self.__class__(deepcopy(self.arg, memo))
            new.a = self.a
            return new
    c = C('argument sketch')
    l.append(c)
    l2 = copy(l)
354 355 356
    print(l == l2)
    print(l)
    print(l2)
Tim Peters's avatar
Tim Peters committed
357
    l2 = deepcopy(l)
358 359 360
    print(l == l2)
    print(l)
    print(l2)
Tim Peters's avatar
Tim Peters committed
361 362
    l.append({l[1]: l, 'xyz': l[2]})
    l3 = copy(l)
363 364 365 366 367
    import reprlib
    print(map(reprlib.repr, l))
    print(map(reprlib.repr, l1))
    print(map(reprlib.repr, l2))
    print(map(reprlib.repr, l3))
Tim Peters's avatar
Tim Peters committed
368
    l3 = deepcopy(l)
369 370 371 372
    print(map(reprlib.repr, l))
    print(map(reprlib.repr, l1))
    print(map(reprlib.repr, l2))
    print(map(reprlib.repr, l3))
373 374

if __name__ == '__main__':
Tim Peters's avatar
Tim Peters committed
375
    _test()