AI Skill Report Card

Using Copy Module

A-83·Aug 22, 2026·Source: Web
13 / 15
Python
import copy # Shallow copy: new outer object, but nested objects are shared references shallow = copy.copy(original) # Deep copy: new outer object AND recursively copies all nested objects deep = copy.deepcopy(original)
Recommendation
Add an example showing memo dict usage for circular references explicitly
14 / 15
  1. Identify the problem: Are you seeing unexpected mutations propagate between two variables that should be independent? This is an aliasing bug — assignment (b = a) does not copy, it just binds a new name to the same object.

  2. Decide copy depth needed:

    • Flat structure (no nested mutables) → copy.copy() is sufficient and cheaper.
    • Nested structures (list of lists, dict of objects, etc.) → use copy.deepcopy().
  3. Check for built-in shortcuts first (often faster/clearer than importing copy):

    • list(original) or original[:] for shallow list copy
    • dict(original) for shallow dict copy
    • original.copy() — most built-in containers have this method
  4. For custom classes, decide if default behavior is enough:

    • Default copy.copy()/copy.deepcopy() copies the __dict__ (shallow/deep respectively).
    • Override __copy__(self) and/or __deepcopy__(self, memo) when the class manages external resources (file handles, locks, sockets) that shouldn't be blindly duplicated.
  5. Handle circular references: deepcopy automatically tracks already-copied objects via the memo dict to avoid infinite recursion — no extra work needed unless implementing __deepcopy__ yourself, in which case pass memo through to recursive copy.deepcopy(x, memo) calls.

  6. Test the copy: mutate the original after copying and confirm the copy is unaffected (for deepcopy) or that only top-level independence holds (for shallow copy).

Recommendation
Include a decision table/flowchart for choosing shallow vs deep vs built-in copy
18 / 20

Example 1: Shallow copy pitfall Input:

Python
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) shallow[0].append(99) print(original)

Output:

Python
[[1, 2, 99], [3, 4]] # inner list mutated because it's shared by reference

Example 2: Deep copy fixes it Input:

Python
import copy original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0].append(99) print(original)

Output:

Python
[[1, 2], [3, 4]] # unaffected, inner lists were fully duplicated

Example 3: Custom __deepcopy__ Input:

Python
import copy class Connection: def __init__(self, socket): self.socket = socket # unpicklable/unshareable resource def __deepcopy__(self, memo): # Don't duplicate the actual socket; share the reference new = Connection.__new__(Connection) memo[id(self)] = new new.socket = self.socket return new conn2 = copy.deepcopy(conn1)

Output:

Python
# conn2 is a new Connection object, but conn2.socket is conn1.socket (same object)
Recommendation
Mention pickle-based deepcopy fallback behavior and when deepcopy fails (unpicklable objects without custom methods)
  • Prefer built-in .copy(), slicing, or constructor calls (list(), dict(), set()) over copy.copy() for simple containers — they're idiomatic and slightly faster.
  • Use copy.deepcopy() whenever objects contain nested mutable structures and true independence is required.
  • When implementing __deepcopy__, always accept and thread through the memo dictionary to correctly handle shared/circular references.
  • For classes holding non-copyable resources (files, sockets, locks, threads), implement __copy__/__deepcopy__ explicitly rather than relying on defaults.
  • Remember atomic/immutable types (int, str, tuple of immutables, frozenset) are returned as-is by copy/deepcopy — no need to copy them manually.
  • Use copy.deepcopy(obj, memo={}) manually only in rare cases where you need to pre-seed the memo (e.g., to force sharing of a specific sub-object).
  • Assuming b = a copies: it doesn't — both names reference the identical object.
  • Using shallow copy on nested structures: leads to subtle bugs where mutating a "copy" affects the original's nested data.
  • Forgetting __deepcopy__ needs memo: skipping it breaks cycle detection and can cause infinite recursion or duplicate objects that should be shared.
  • Deep-copying unpicklable/unshareable resources by default: sockets, file handles, and thread locks generally cannot (and should not) be deep-copied — override __deepcopy__ to handle them explicitly.
  • Overusing deepcopy for performance-critical code: it's recursive and can be slow on large or deeply nested structures; use shallow copy or restructure data when full independence isn't needed.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
13/15
Workflow
14/15
Examples
18/20
Completeness
18/20
Format
14/15
Conciseness
14/15