Labelled boxes on a shelf

Variables & Data Types

The analogy

A variable is a box with a label taped on the front. Write age on the label, put 12 inside, and from now on anyone who asks for "age" gets 12 โ€” until you swap the contents. The box does not care what it held yesterday; it holds exactly one thing at a time. Data types are just box shapes: a whole-number box (integer), a decimal box (float), a text box (string), and a tiny switch that is only ever on or off (boolean). The shape matters because the machine handles each one differently โ€” you cannot pour "hello" into a number box and expect maths to work on it. One more Python secret: the label is a sticky note, not part of the box. Peel "x" off the number 5 and stick it on the word "five", and Python shrugs โ€” the LABEL moved to a different box; nothing broke. Some stricter languages (Java, C) glue each label to one box shape forever and refuse the swap; Python never glues.

Visualizer

Boxes with labels

step 1 / 5
MEMORY โ€” the shelf of boxes
age: int = 12
(no box called name yet)
(no box called lights_on yet)

One box so far: the label says age, the contents say 12, and the box shape is "whole number".

๐Ÿ“– In depth โ€” the full reference

Every built-in data type in Python (CPython 3.12, 64-bit)

typeexamplememory (sys.getsizeof)mutable?notes
int4228 bytes small; +4 per extra 30 bitsnoARBITRARY precision โ€” never overflows, just grows
float3.1424 bytesnoIEEE-754 double: 15โ€“17 significant digits; 0.1+0.2 != 0.3
boolTrue28 bytesnoa subclass of int โ€” True == 1, so sum([True,True]) == 2
complex2+3j32 bytesnotwo doubles: real + imaginary
str"hi"49 + ~1โ€“4 bytes/charnoUnicode; width adapts to the widest char (emoji cost 4/char)
bytesb'hi'33 + 1 byte/charnoraw 0โ€“255 values; what files and networks actually carry
NoneTypeNone16 bytes (one shared object)nothe "no value" singleton; test with `is None`
list[1, 2]56 + 8/slot (overallocates ~12%)YESthe dynamic array of Module 2
tuple(1, 2)40 + 8/slotnoimmutable list; hashable, so usable as a dict key
dict{'a': 1}64 empty; grows in powers of 2YESthe hash map of Module 2
set{1, 2}216 emptyYEShash table without values; frozenset is its immutable twin
rangerange(10**9)48 bytes regardless of lengthnolazy โ€” computes values on demand

The rules

  • Names bind, boxes don't exist twice: `b = a` copies a REFERENCE. For immutable values that's indistinguishable from a copy; for a list, both names now point at ONE list.
  • Identifiers: letters, digits, underscores; can't start with a digit; case-sensitive (Age โ‰  age); can't be a keyword (`if`, `class`, `for`โ€ฆ). Convention: snake_case for variables, UPPER_CASE for constants.
  • Immutable types (int, float, str, tuple, bool) can never change in place โ€” every "modification" builds a new object. That's why `s += "!"` in a loop is O(nยฒ).
  • Only immutable (hashable) values may be dict keys or set members โ€” a list can't, a tuple can.
  • Check types with isinstance(x, int), never `type(x) == int` (isinstance respects subclasses โ€” remember bool!).
  • Integer division of big ints is exact โ€” Python ints never silently wrap around like C/Java ints (the Ariane 5 class of bug can't happen here).

See it yourself

import sys
print(sys.getsizeof(0))          # 28
print(sys.getsizeof(10**100))    # 72 โ€” the int GREW
print(sys.getsizeof(""))        # 49
print(sys.getsizeof("hi"))      # 51
print(sys.getsizeof([]))         # 56
print(True + True)                # 2 (bool is an int!)
print(0.1 + 0.2 == 0.3)          # False โ€” floats approximate
age = 12          # int
price = 9.99      # float
name = "Ada"      # str
lights_on = True  # bool

age = age + 1     # rebind: the box now holds 13
print(type(age))  # <class 'int'>
Check yourself

x = 5, then x = "five". In Python, what is x now?

Practice โ€” write it yourself

Write next_age(age): store age + 1 in a variable and return it. Your first box.

Python 3 ยท runs in your browser ยท your draft is saved locally
๐Ÿ“ My notessaved in this browser