Variables, objects and types
In Python, a variable isn’t a box that holds a value — it’s a name attached to an object. That one idea explains aliasing, mutability and a whole family of confusing bugs. See names and objects move as code runs.
In this lecture you will
- Explain that Python names refer to objects rather than containing values
- Predict the effect of assignment, rebinding and mutation
- Distinguish mutable from immutable types
- Use == and is correctly
In many languages you are taught that a variable is a box: you put a value in it, and assigning to another variable copies the value into a second box. Python works differently, and understanding exactly how removes a whole class of confusing bugs.
Everything is an object
Every value in Python — a number, a string, a list, a function, even a class — is an object. Each object has three things:
- Type
- What kind of object it is — int, str, list, dict — which decides what you can do with it. Check it with type(x).
- Value
- The data it represents, such as 42 or the characters of a string.
- Identity
- Which object it is. Two objects can have equal values but different identities. id(x) shows a number unique to the object while it exists.
Names are labels, not boxes
A variable in Python is a name that refers to an object. The statement x = 42 means: make (or find) an object with value 42, and attach the label x to it. Assignment never copies an object — it only binds a name.
Step through the code below and watch the arrows between names and objects.
- x = 42An int object with value 42 is created, and the name x is bound to it.
- y = xNo copy is made. y becomes a second name for the very same object.
- x = x + 1x + 1 creates a new object, 43, and x is rebound to it. y still points at 42 — ints are immutable, so 42 itself never changed.
- a = [1, 2]A list object is created and bound to a. Lists are mutable: their contents can change.
- b = aAgain no copy: a and b are two names for one list. This is called aliasing.
- b.append(3)append changes the list object in place. Both a and b see [1, 2, 3], because there is only one list.
- c = a.copy()copy() creates a new list with the same contents. c points at a different object.
- a == c, a is c== compares values: True, the contents are equal. is compares identity: False, they are different objects.
Mutable and immutable types
Whether an object can change after it is created depends on its type:
| Immutable — cannot change | Mutable — can change in place |
|---|---|
int, float, bool, str, tuple, frozenset, None | list, dict, set, most objects you create from your own classes |
With immutable objects, every “change” creates a new object: name.upper() returns a new string and leaves the original alone. With mutable objects, methods like append, update and add change the object itself — and every name bound to it sees the change.
Dynamic typing
In Python, types belong to objects, not names. A name can refer to a string now and an integer later:
value = "42" # a str
value = int(value) # now the name refers to an int
print(type(value)) # <class 'int'>
That flexibility makes Python quick to write. The trade-off is that type mistakes surface only when the code runs — which is why modern teams add optional type hints and checkers, covered in module 3.
Because the object decides what an operation means, the same line of code can work, do something surprising or fail, depending on what it receives. Explore six everyday operations on seven kinds of value:
Every result and error message here comes from CPython 3.14. Notice the difference between a TypeError (the operation makes no sense for this type) and a ValueError (right type, wrong value).
Comparing: == versus is
a == basks: do these objects have equal values?a is basks: are these the very same object?
Use == for almost everything. Use is to check for None — if result is None: — because there is only ever one None object.
- One list, repeated[[0] * 3] * 3 builds a single inner list, then repeats a reference to it three times. The outer list has three slots, but they all point to the same object.
- Change one cellgrid[0][0] = 1 follows slot 0 to the inner list and changes its first cell.
- Every row changesPrinting the grid shows the change in every row, because every row is that same list.
- The fixA list comprehension evaluates [0] * 3 once per row, so it builds three separate inner lists.
- Only one row changesNow grid[0][0] = 1 changes only the first row. Use a comprehension whenever you need rows of mutable objects.
With names and objects clear, the next lecture teaches a program to make decisions and repeat work: conditionals and loops.
Key takeaways
- Every value in Python is an object with a type, a value and an identity.
- Assignment binds a name to an object; it never copies the object.
- Mutating an object is visible through every name that refers to it; rebinding a name affects only that name.
- Use == to compare values and is to check whether two names refer to the very same object (mostly for None).
Check your understanding
3 questions · answers explainedQ1After a = [1, 2]; b = a; b.append(3), what is a?
Q2After x = 10; y = x; x = x + 5, what is y?
Q3Which is the idiomatic way to check whether a variable holds None?