Module 1 · Getting started

Variables, objects & types

Foundations 16 min read The mental model that prevents a whole class of bugs

In many languages a variable is a box that holds a value. In Python it is better to think of a variable as a name tag attached to an object. The object (the number, the text, the list) lives on its own. The name just refers to it. x = 5 means "attach the tag x to the object 5". This small shift explains why changing a list through one name changes it everywhere, while "changing" a number never does.

🏷️

Luggage tags, not boxes

Objects are suitcases in a hall. Names are luggage tags tied to them. You can tie two tags to the same suitcase, and anything packed into that suitcase is visible whichever tag you follow. Moving a tag to a different suitcase does nothing to the first suitcase. Python quietly throws away suitcases that have no tags left.

1. Assignment attaches a name

city = "Kochi"
population = 677_381          # underscores make big numbers readable; they are ignored
area_km2 = 94.88
is_coastal = True
mayor = None                  # None: "no value (yet)"

for value in (city, population, area_km2, is_coastal, mayor):
    print(f"{value!r:>10} is a {type(value).__name__}")
'Kochi' is a str 677381 is a int 94.88 is a float True is a bool None is a NoneType

Every object has a type that decides what you can do with it: you can add two ints and upper-case a string, but not upper-case an int. Python checks types while the program runs. That is dynamic typing: a name can refer to an int now and a string later, and the object always knows its own type.

NAMES OBJECTS city home "Kochi"str total 10 (no tags) 15 home = city → two tags, one object total = total + 5 makes a new object and moves the tag

2. Same object or equal objects?

id(x) gives an object's identity, a number unique while the object exists. a is b asks "are these the same object?". a == b asks "do these have equal values?". Usually you want ==.

a = [1, 2, 3]
b = a                  # another tag on the SAME list
c = [1, 2, 3]          # a different list that happens to be equal

print("a == b:", a == b, "| a is b:", a is b)
print("a == c:", a == c, "| a is c:", a is c)

b.append(4)            # change the object through the name b...
print("a is now", a)   # ...and a sees it: they are the same object
print("c is still", c)
a == b: True | a is b: True a == c: True | a is c: False a is now [1, 2, 3, 4] c is still [1, 2, 3]
The one place to use "is"

Compare with None using is: if result is None:. For everything else (numbers, strings, lists) use ==. x is 5 sometimes appears to work because CPython reuses small numbers, then fails for larger ones. Python even warns you about it.

3. Mutable and immutable objects

Some objects can change in place (mutable): lists, dictionaries, sets. Others can never change (immutable): numbers, strings, tuples, True/False, None. When you "change" an immutable object, Python actually makes a new object and moves the name to it:

score = 10
before = id(score)
score += 5                                   # a NEW int object; the name moves
print("int: same object after += ?", id(score) == before)

word = "tea"
before = id(word)
word += "pot"                                # strings too: a new string
print("str: same object after += ?", id(word) == before, "→", word)

items = ["tea"]
before = id(items)
items += ["pot"]                             # a list changes IN PLACE
print("list: same object after += ?", id(items) == before, "→", items)
int: same object after += ? False str: same object after += ? False → teapot list: same object after += ? True → ['tea', 'pot']
Immutable (can't change)Mutable (can change in place)
int, float, bool, str, tuple, frozenset, Nonelist, dict, set, most objects you create from classes
safe to share between names: nobody can change themsharing means changes are visible through every name (lesson 08 shows how to copy)

4. Useful assignment forms

x, y = 3, 7                    # assign several names at once
x, y = y, x                    # swap: no temporary variable needed
print("swapped:", x, y)

count = 0
count += 1                     # count = count + 1
count *= 10                    # count = count * 10
print("count:", count)

width = height = 100           # both names → the same object (fine for immutable values)
print(width, height)

TAX_RATE = 0.18                # UPPER_CASE = "please treat as a constant" (a convention only)
print(f"{TAX_RATE:.0%}")
swapped: 7 3 count: 10 100 100 18%

5. Naming rules and conventions

Rules (enforced)

Letters, digits and underscores; cannot start with a digit; case-sensitive (total ≠ Total); cannot be a keyword such as class, for, if, None.

Conventions (PEP 8)

snake_case for variables and functions, PascalCase for classes, UPPER_CASE for constants. Descriptive names: unit_price, not up or x2.

A classic beginner accident is naming a variable after a built-in, which hides the built-in for the rest of the program:

list = ["tea", "rice"]          # 'list' now means THIS list, not the built-in type
letters = list("abc")           # so this fails
Traceback (most recent call last): File "example.py", line 2, in <module> letters = list("abc") # so this fails TypeError: 'list' object is not callable

Pick another name (items, groceries) and the built-in keeps working. Editors warn you about this.

6. None: the "nothing here" value

discount = None                         # not decided yet
print(type(discount).__name__, discount is None)

discount = 0                            # zero is a value, not "nothing"
print("zero is None?", discount is None)

def find_price(item):                   # a function that finds nothing returns None
    return {"tea": 120}.get(item)
print(find_price("coffee"))
NoneType True zero is None? False None

Recap

  • Names refer to objects. Assignment attaches a name; it never copies an object.
  • Every object has a type, checked while the program runs (dynamic typing).
  • == compares values, is compares identity. Use is only with None.
  • Immutable objects never change (a new object is made); mutable ones change in place, visibly through every name.

Checkpoint

1 · a = [1]; b = a; b.append(2). What is a?
b = a attaches a second name to the same list. Appending through either name changes that one list.
2 · n = 10; m = n; n += 1. What is m?
Ints are immutable. n += 1 creates a new int 11 and moves the name n. m still refers to 10.
3 · How should you test whether result has no value?
None is a single object, so identity is the precise test. not result would also be true for 0, "" and [].