3 / 14
Guide Book · Chapter 3

Names, objects & variables

Python variables are labels on objects, not boxes. This one idea explains aliasing, `is` vs `==`, and mutation.

Variables are names, not boxes

In many languages a variable is a box that holds a value. In Python a variable is a name bound to an object. Assignment never copies anything; it just points a name at an object.

python
a = [1, 2, 3]
b = a            # b now points at the SAME list
b.append(4)
print(a)         # [1, 2, 3, 4], because there is only one list
print(a is b)    # True: same object

Every object has three things:

PropertyHow to see itCan it change?
identityid(obj)never, for the object's lifetime
typetype(obj)never
valueprinting itonly if the type is mutable
python
x = "hello"
print(id(x), type(x), x)

💡 Tip: Run the first example, then open Inspect: a and b show the same highlighted id. That's aliasing, made visible.

== vs is

== asks "equal value?" (it calls __eq__). is asks "the very same object?" (it compares identities).

python
a = [1, 2]
b = [1, 2]
print(a == b)   # True: same contents
print(a is b)   # False: two different lists
print(None is None)  # use `is` for None, True, False

Mutable vs immutable

Immutable (can't change in place)Mutable (can change in place)
int, float, bool, str, tuple, frozenset, byteslist, dict, set, bytearray, most class instances

"Changing" an immutable value really creates a new object and rebinds the name:

python
s = "hi"
old_id = id(s)
s += "!"                 # builds a new string
print(s, id(s) == old_id)  # hi! False

nums = [1]
old_id = id(nums)
nums += [2]              # lists extend in place
print(nums, id(nums) == old_id)  # [1, 2] True
python
import sys

data = []
print(sys.getrefcount(data) - 1)  # -1: getrefcount's own argument
alias = data
holder = [data, data]
print(sys.getrefcount(data) - 1)
python
a = 256
b = 256
print(a is b)          # True: both names use the cached 256
c = int("1000")
d = int("1000")
print(c is d, c == d)  # False True: two separate 1000 objects

Deleting a name

del removes a name, not an object. The object disappears only when no references are left.

python
a = [1, 2]
b = a
del a
print(b)   # the list is still alive through b

🧭 Scenario: You write row = [0] * 3; grid = [row] * 3, set grid[0][0] = 1, and every row changes. All three rows are the same list object. Build independent rows instead: grid = [[0] * 3 for _ in range(3)].

python
row = [0] * 3
grid = [row] * 3
grid[0][0] = 1
print(grid)   # every row changed!

grid = [[0] * 3 for _ in range(3)]
grid[0][0] = 1
print(grid)   # only the first row
main.py
Loading editor…
No output yet
Press Run or ⌘↵ to compile and run your code.

Search

Jump to a lesson or a past run