Read first

Copying a container that holds other mutable objects raises a question: copy just the outer box, or everything inside too?

  • Shallow copy: a new outer container, but the items inside are the same objects as before.
  • Deep copy: new copies of everything, recursively.

How to make each

ShallowDeep
Pythonlst.copy(), list(lst), lst[:], dict.copy(), copy.copy(x)copy.deepcopy(x)
JavaScript[...arr], {...obj}, Object.assign({}, obj)structuredClone(obj)

Example

import copy
config = {"retries": 3, "tags": ["a"]}
s = config.copy()
d = copy.deepcopy(config)
s["tags"].append("b")
print(config["tags"])   # ['a', 'b']  the shallow copy shares the inner list
print(d["tags"])        # ['a']
const config = { retries: 3, tags: ['a'] };
const s = { ...config };
const d = structuredClone(config);
s.tags.push('b');
console.log(config.tags, d.tags);   // [ 'a', 'b' ] [ 'a' ]

Traps

  • A shallow copy of a flat list of numbers or strings is enough: those are immutable.
  • JSON.parse(JSON.stringify(x)) as a deep copy loses dates, undefined, Map, Set and functions. Prefer structuredClone.
  • Deep copies cost time and memory. Copy only what you will change.

Check yourself