Skip to main content

Lib/copy.py

Source:

cpython 3.14 @ ab2d84fe1023/Lib/copy.py

Lib/copy.py provides copy (shallow copy) and deepcopy (recursive deep copy). copy dispatches through __copy__ or the type's __reduce_ex__ protocol. deepcopy uses a memo dict keyed on object identity to handle cycles and shared references, and dispatches through __deepcopy__, __reduce_ex__, or a dispatch table of type-specific copiers.

Map

LinesSymbolRole
1-50imports, _copy_dispatch, _deepcopy_dispatchType dispatch tables
51-120copyShallow copy dispatcher
121-250deepcopyDeep copy with memo dict
251-300_reconstruct, _deepcopy_atomic, helpersReconstruction from __reduce_ex__; atomic-type no-op copiers

Reading

copy dispatch

copy(x) first checks _copy_dispatch for built-in types (int, float, str, etc. all return x unchanged since they are immutable). Then it looks for __copy__. Finally it falls back to __reduce_ex__(4) to get a reconstruction recipe.

# CPython: Lib/copy.py:51 copy
def copy(x):
cls = type(x)
copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
copier = getattr(cls, '__copy__', None)
if copier is not None:
return copier()
reductor = getattr(cls, '__reduce_ex__', None)
rv = reductor(4)
return _reconstruct(x, None, *rv)

deepcopy memo dict

deepcopy passes a memo dict through every recursive call. Before copying, it checks memo[id(x)]; if present, the object was already copied and the existing copy is returned. This handles cycles (a list containing itself) and ensures shared references remain shared in the copy.

# CPython: Lib/copy.py:121 deepcopy
def deepcopy(x, memo=None, _nil=[]):
if memo is None:
memo = {}
d = id(x)
y = memo.get(d, _nil)
if y is not _nil:
return y
cls = type(x)
copier = _deepcopy_dispatch.get(cls)
if copier is not None:
y = copier(x, memo)
...
memo[d] = y
return y

Atomic types

_deepcopy_atomic is registered for immutable types like int, float, str, bytes, bool, NoneType, type, range, slice. It simply returns the original object without copying, since immutable objects can be safely shared.

gopy notes

Not yet ported. The planned package path is module/copy/. A Go port would use reflect.DeepCopy-style recursion with a map[uintptr]interface{} memo dict. The __copy__/__deepcopy__ protocol hooks would check for corresponding Go interface methods.