Python’s copy module duplicates objects with or without shared references. import copy. copy: copy.copy(obj) — shallow copy; new container, same element references. deepcopy: copy.deepcopy(obj) — fully independent recursive copy. memo: copy.deepcopy(obj, memo={}) — memo dict caches already-copied objects, handles cycles. copy: def __copy__(self): ... — custom shallow copy. deepcopy: def __deepcopy__(self, memo): ... — custom deep copy. copy vs slice: lst[:] is a shallow copy; copy.copy(lst) is equivalent. copy of dict: {**d} or d.copy() shallow; copy.deepcopy(d) deep. Shallow copy shares inner mutables: a = [[1]]; b = copy.copy(a); b[0][0] = 99; a[0][0] → 99. Deep copy is independent: b[0][0] = 99; a[0][0] → still 1. copy of dataclass: dataclasses.replace(obj, field=new_val) for field-level updates; copy.copy for full shallow clone. Copying class instances: copy.copy calls __copy__ or creates new instance and shallow-copies __dict__. Performance: copy.copy is fast; copy.deepcopy can be slow for large graphs — profile before relying on it in hot paths. Claude Code generates undo-redo stacks, configuration snapshots, event-sourced aggregates, and safe default value patterns.
CLAUDE.md for copy
## copy Stack
- Stdlib: import copy
- Shallow: copy.copy(obj) — new container, shared element refs
- Deep: copy.deepcopy(obj) — fully independent recursive clone
- Dataclass update: dataclasses.replace(obj, field=new_val)
- Custom: def __copy__(self) / def __deepcopy__(self, memo)
- Cycle-safe: copy.deepcopy(obj, {}) — memo handles self-referential structures
copy Object Cloning Pipeline
# app/copyutil.py — shallow, deep, custom, dataclass, undo-redo, snapshot
from __future__ import annotations
import copy
import dataclasses
from dataclasses import dataclass, field
from typing import Any, Generic, TypeVar
T = TypeVar("T")
# ─────────────────────────────────────────────────────────────────────────────
# 1. Basic copy helpers
# ─────────────────────────────────────────────────────────────────────────────
def shallow_copy(obj: T) -> T:
"""
Return a shallow copy of obj.
Example:
a = [1, [2, 3]]
b = shallow_copy(a)
b[0] = 99 # a[0] unchanged
b[1][0] = 99 # a[1][0] ALSO changes (shared inner list)
"""
return copy.copy(obj)
def deep_copy(obj: T) -> T:
"""
Return a fully independent deep copy of obj.
Example:
a = {"users": [{"name": "Alice"}]}
b = deep_copy(a)
b["users"][0]["name"] = "Bob" # a unchanged
"""
return copy.deepcopy(obj)
def clone(obj: T, **overrides) -> T:
"""
Deep-copy an object and optionally override attributes.
Works best with dataclasses (uses dataclasses.replace) and plain objects.
Example:
user2 = clone(user, name="Bob", active=False)
"""
if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
return dataclasses.replace(obj, **overrides)
cloned = copy.deepcopy(obj)
for k, v in overrides.items():
setattr(cloned, k, v)
return cloned
def copy_dict(d: dict, deep: bool = False) -> dict:
"""
Copy a dictionary, shallow or deep.
Example:
cfg_copy = copy_dict(config, deep=True)
"""
return copy.deepcopy(d) if deep else {**d}
def copy_list(lst: list, deep: bool = False) -> list:
"""
Copy a list, shallow or deep.
Example:
safe = copy_list(mutable_defaults, deep=True)
"""
return copy.deepcopy(lst) if deep else lst[:]
# ─────────────────────────────────────────────────────────────────────────────
# 2. Custom __copy__ / __deepcopy__ patterns
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class Config:
"""
A configuration object that supports safe shallow and deep copying.
Shallow copy shares nested dicts; deep copy is fully independent.
Example:
cfg = Config(host="localhost", port=8080, options={"debug": True})
copy1 = copy.copy(cfg) # shares options dict
copy2 = copy.deepcopy(cfg) # fully independent
"""
host: str
port: int
options: dict[str, Any] = field(default_factory=dict)
def __copy__(self) -> "Config":
return Config(host=self.host, port=self.port, options=self.options)
def __deepcopy__(self, memo: dict) -> "Config":
return Config(
host=self.host,
port=self.port,
options=copy.deepcopy(self.options, memo),
)
def with_option(self, key: str, value: Any) -> "Config":
"""Return a new Config with one option changed (immutable-style)."""
return dataclasses.replace(self, options={**self.options, key: value})
class ExcludeFromCopy:
"""
Mixin: excludes specified attributes from deepcopy (e.g., locks, connections).
Example:
class DBRepo(ExcludeFromCopy, exclude={"_conn", "_lock"}):
def __init__(self):
self._conn = open_connection()
self._lock = threading.Lock()
self.data = {}
"""
_exclude_from_copy: set[str] = set()
def __init_subclass__(cls, exclude: set[str] | None = None, **kwargs):
super().__init_subclass__(**kwargs)
cls._exclude_from_copy = exclude or set()
def __deepcopy__(self, memo: dict) -> "ExcludeFromCopy":
cls = self.__class__
new = cls.__new__(cls)
memo[id(self)] = new
for k, v in self.__dict__.items():
if k in self._exclude_from_copy:
setattr(new, k, None) # or a fresh default
else:
setattr(new, k, copy.deepcopy(v, memo))
return new
# ─────────────────────────────────────────────────────────────────────────────
# 3. Undo-redo stack
# ─────────────────────────────────────────────────────────────────────────────
class UndoStack(Generic[T]):
"""
Undo/redo stack that deep-copies state on each push.
Each state change creates a snapshot; undo/redo navigate history.
Example:
stack = UndoStack({"items": []})
stack.push({"items": ["a"]})
stack.push({"items": ["a", "b"]})
stack.undo() # → {"items": ["a"]}
stack.undo() # → {"items": []}
stack.redo() # → {"items": ["a"]}
"""
def __init__(self, initial: T, max_states: int = 50) -> None:
self._history: list[T] = [copy.deepcopy(initial)]
self._future: list[T] = []
self._max: int = max_states
@property
def current(self) -> T:
return self._history[-1]
def push(self, state: T) -> None:
"""Save a deep copy of state; clears redo stack."""
self._history.append(copy.deepcopy(state))
if len(self._history) > self._max:
self._history.pop(0)
self._future.clear()
def undo(self) -> T | None:
"""Step back one state and return it, or None if at start."""
if len(self._history) <= 1:
return None
self._future.append(self._history.pop())
return copy.deepcopy(self._history[-1])
def redo(self) -> T | None:
"""Step forward one state and return it, or None if at end."""
if not self._future:
return None
state = self._future.pop()
self._history.append(state)
return copy.deepcopy(state)
def can_undo(self) -> bool:
return len(self._history) > 1
def can_redo(self) -> bool:
return bool(self._future)
def __len__(self) -> int:
return len(self._history)
# ─────────────────────────────────────────────────────────────────────────────
# 4. Safe defaults pattern
# ─────────────────────────────────────────────────────────────────────────────
class SafeDefaultFactory:
"""
Stores a prototype and returns a deep copy each time __call__ is invoked.
Prevents accidental sharing of mutable defaults.
Example:
make_user = SafeDefaultFactory({"roles": ["viewer"], "settings": {}})
u1 = make_user()
u1["roles"].append("admin")
u2 = make_user() # {"roles": ["viewer"], "settings": {}} — unchanged
"""
def __init__(self, prototype: Any) -> None:
self._proto = prototype
def __call__(self) -> Any:
return copy.deepcopy(self._proto)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== copy demo ===")
print("\n--- shallow vs deep ---")
original = {"users": [{"name": "Alice", "scores": [90, 95]}]}
shallow = shallow_copy(original)
deep = deep_copy(original)
shallow["users"][0]["name"] = "Shallow-Bob"
deep["users"][0]["name"] = "Deep-Bob"
print(f" original name: {original['users'][0]['name']!r}") # Shallow-Bob (shared!)
original["users"][0]["name"] = "Alice"
print(f" deep name: {deep['users'][0]['name']!r}") # Deep-Bob (independent)
print("\n--- clone (dataclass) ---")
@dataclass
class User:
name: str
email: str
active: bool = True
tags: list = field(default_factory=list)
alice = User("Alice", "[email protected]", tags=["admin"])
bob = clone(alice, name="Bob", email="[email protected]")
print(f" alice: {alice}")
print(f" bob: {bob}")
bob.tags.append("user")
print(f" alice tags after bob.tags.append: {alice.tags}") # independent
print("\n--- Config with __copy__ / __deepcopy__ ---")
cfg = Config("localhost", 8080, {"debug": True, "timeout": 30})
cfg2 = copy.deepcopy(cfg)
cfg2.options["debug"] = False
print(f" original debug: {cfg.options['debug']}") # True
print(f" copy debug: {cfg2.options['debug']}") # False
cfg3 = cfg.with_option("timeout", 60)
print(f" with_option: {cfg3.options}")
print(f" original still: {cfg.options}")
print("\n--- UndoStack ---")
stack = UndoStack({"items": []})
for item in ["a", "b", "c"]:
state = copy.deepcopy(stack.current)
state["items"].append(item)
stack.push(state)
print(f" current: {stack.current}")
u1 = stack.undo()
u2 = stack.undo()
print(f" after 2 undos: {stack.current}")
r1 = stack.redo()
print(f" after redo: {stack.current}")
print(f" can_undo={stack.can_undo()} can_redo={stack.can_redo()}")
print("\n--- SafeDefaultFactory ---")
make_user = SafeDefaultFactory({"roles": ["viewer"], "settings": {}})
u1 = make_user()
u1["roles"].append("admin")
u2 = make_user()
print(f" u1 roles: {u1['roles']}")
print(f" u2 roles: {u2['roles']}") # still ["viewer"]
print("\n=== done ===")
For the pickle alternative — pickle.loads(pickle.dumps(obj)) performs a deep copy of any picklable object and is sometimes faster than copy.deepcopy for very large plain-data objects; however it requires all referenced types to be picklable and carries the security warning that loading untrusted pickle data is unsafe — use pickle round-trip as a performance optimization for known-safe, large dict/list structures when profiling shows deepcopy is a bottleneck, copy.deepcopy as the default safe approach. For the dataclasses.replace alternative — dataclasses.replace(obj, **changes) creates a shallow copy of a dataclass with specified field overrides in one call, handling __post_init__ validation automatically; copy.copy + manual setattr is more error-prone with dataclasses — use dataclasses.replace for immutable-style functional updates to dataclass instances, copy.copy/copy.deepcopy for general Python objects, nested structures, or when you need full independence of ALL fields including nested containers. The Claude Skills 360 bundle includes copy skill sets covering shallow_copy()/deep_copy()/clone()/copy_dict()/copy_list() copy helpers, Config with copy/deepcopy custom copy protocol, ExcludeFromCopy mixin for skipping unserializable attributes, UndoStack generic undo-redo with state snapshots, and SafeDefaultFactory prototype-based mutable default prevention. Start with the free tier to try object cloning patterns and copy pipeline code generation.