Values, names, and mutation
Python names point at objects. Assignment binds a name to an object; it does not copy the object. Immutable values such as integers, strings, and tuples can be rebound without changing the original object. Lists, dictionaries, and sets can be mutated in place, which means two names can observe the same change. This distinction explains why a default list argument, a shallow copy, or a reused accumulator can leak state between calls.
Choose a representation that makes invalid states awkward. Use None for a genuinely absent value, not for every kind of failure. Keep units and meanings visible in names. A variable called timeout_seconds prevents a caller from passing milliseconds by accident more effectively than a comment saying “timeout”.
Copy only when ownership changes. A shallow copy duplicates the outer container while retaining nested objects. A deep copy may preserve the wrong relationships and can copy resources that should never be copied.
is asks whether two names refer to the same object; == asks whether their values compare equal. Use is None for the singleton None. Do not rely on interning or implementation details for strings and integers. When a mutation surprises you, print id() values at the boundary, then replace implicit sharing with an explicit copy or a function that owns the object.
Micro-lab in the app
Predict, run, change or break, explain: alias the list, copy it, and explain which output changes.
names = ['Ada', 'Lin']
selected = names
selected.append('Mina')
print(names)A function appends to a list supplied by its caller, and the caller's list changes. What is the sound interpretation?
You need a function that uses an empty mapping when no configuration is provided. Which signature avoids shared state across calls?
Notes are kept with your account, alongside your progress and your gate claims. The lesson itself is readable without one.