CodeRigor

FREE LESSON

Names, objects & copying

Bindings, identity, mutable containers, shallow copies and fresh defaults; keep experiment inputs independent.

A Python name refers to an object. b = a creates another binding to the same object; it does not copy a list. Assignment can rebind a name, while a method such as append changes the existing object. Indentation groups statements; # starts a comment and print displays a value.

Follow the arrows: assignment shares an object; rebinding changes one arrow.

Two names, one list
start / 3
Both a and b refer to the same mutable list. Step through mutation, then rebind b to an independent list.
Two names, one list
Both a and b refer to the same mutable list. Step through mutation, then rebind b to an independent list.
Python
scores = [1, 2]
alias = scores
alias.append(3)
print(scores)  # [1, 2, 3]
alias = [9]
print(scores)  # still [1, 2, 3]

Use == for values. is asks whether two references name the same object; reserve is None for the absence sentinel. Integers, floats, strings and tuples are immutable, but a tuple can still contain a mutable list.

A list slice copies the outer list. For a matrix represented by lists of lists, copying just the outer list still shares the rows:

Python
matrix = [[1, 2], [3, 4]]
shallow = matrix[:]
shallow[0][0] = 7
independent = [row[:] for row in matrix]
independent[0][0] = 8
print(matrix)  # [[7, 2], [3, 4]]

Function defaults are evaluated when the function is defined. A default [] can therefore collect data across calls. Use None, then construct a fresh container in the call. A function starts with def name(arguments): and returns a result with return. The build's signatures are supplied; focus on how many independently mutable containers each result needs.

In an experiment, aliasing a baseline's data into an intervention can change both conditions. The outputs can look plausible while the comparison loses its meaning. Test independence by mutating one output and inspecting its sibling and input, rather than checking only initial equality.

For nested data, copying the outer container still leaves the original rows shared.

Outer copy versus independent rows
A shallow copy changes the outer container only. The build needs a separate list for every numeric row.
Outer copy versus independent rows
A shallow copy changes the outer container only. The build needs a separate list for every numeric row.

Before the fill: draw the outer list and each row as separate boxes. For [[0]] * 3, how many inner lists exist? Then implement a row copy and a configuration update without changing the caller's values. These tasks use numeric rows and flat dictionaries; recursively copying arbitrary objects is outside their contract.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Focus on aliasing versus cloning and the nested-list examples. Then follow the lesson diagram through mutation and rebinding before attempting the independent-copy build.