Programming Foundations
The whole module on one page β analogy on the left of your memory, definition on the right. Print it (Ctrl/Cmd+P) and stick it above your desk.
A variable binds a name to a value held in memory. In statically typed languages the declared type fixes what the variable may hold and how many bytes it occupies; in dynamically typed languages like Python the VALUE carries the type and the name may rebind freely.
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'>
Type casting converts a value from one type to another. Explicit casts β int(x), float(x), str(x) β are conversions you request; int() on a float TRUNCATES toward zero (use round() for rounding).
raw = input() # user types 12 -> "12" (a string!)
age = int(raw) # cast: "12" -> 12
print(age + 1) # 13
print(int(3.9)) # 3 (truncates, never rounds)
print(float("2.5")) # 2.5
print(str(42) + "!") # "42!"I/O is how a program exchanges data with the world outside its memory. In Python, input(prompt) blocks until the user submits a line and ALWAYS returns str; print(*args) writes to standard output, coercing arguments to str and appending a newline (suppress with end="").
name = input("Name? ") # IN slot (always a string)
age = int(input("Age? ")) # IN + cast
print(f"Hi {name}!") # OUT slot
print(f"Next year you will be {age + 1}.")Operator families: arithmetic (+ - * / // % **), comparison (== != < <= > >=, returning bool), logical (and, or, not β with short-circuit evaluation: the right side is not even evaluated if the left decides the answer), and assignment shorthands (+=, -=). Precedence follows mathematics β ** before * / // %, before + -, before comparisons, before not/and/or β and parentheses override it.
print(7 / 2) # 3.5 true division print(7 // 2) # 3 floor division print(7 % 2) # 1 remainder -> odd! print(2 ** 10) # 1024 power hour = (11 + 3) % 12 # 2 o'clock β wrapping is_even = (n % 2 == 0)
Conditionals branch control flow on boolean expressions. Python evaluates an if/elif/else chain top-down and executes only the first suite whose condition is truthy β subsequent conditions are never evaluated.
score = 73
if score >= 80: # most specific first!
grade = "great"
elif score >= 50:
grade = "pass"
else:
grade = "retry"
print(grade) # passfor iterates over an iterable (list, string, range, dict), binding each element in turn; range(n) yields 0..n-1, and enumerate(xs) yields (index, item) pairs when you need both. while re-tests its condition before every pass and requires the body to make progress toward falsity β forgetting i += 1 is the classic infinite loop.
total = 0
for price in [4, 7, 2]: # known laps
total += price
print(total) # 13
n = 1
while n < 100: # unknown laps
n = n * 2
print(n) # 128
for i, ch in enumerate("abc"):
print(i, ch) # 0 a / 1 b / 2 cdef name(params): binds a reusable code object; calling it pushes a stack frame holding its local bindings, and return pops the frame and hands back a value (None if omitted). Scope follows LEGB β Local, Enclosing, Global, Built-in: a name is resolved in the innermost scope that defines it, and assignment inside a function creates a LOCAL unless declared global/nonlocal.
def price_with_tax(price, rate=0.08):
tax = price * rate # local: dies at return
return price + tax
total = price_with_tax(10.0) # 10.8
print(total)
# print(tax) # NameError β the kitchen is goneTracing is manual execution: maintain a table of variable β value, apply one statement at a time, and record the output exactly. Discipline points: evaluate the right-hand side fully before assigning; on a loop, re-enter the condition check each iteration and write the new bindings; on a function call, open a fresh column for its locals and close it at return.
total = 0
for n in [3, 1, 4]:
if n % 2 == 1: # odd?
total += n
print(n, total) # trace line
# 3 3
# 1 4
# 4 4
print("final:", total) # final: 4Runtime scales with input size n, and the growth SHAPE matters more than the constant: one pass over n items does cΒ·n work (linear); comparing all pairs does ~nΒ²/2 (quadratic); halving the search space each step does logβ(n) (logarithmic β 1,000,000 items in 20 steps). Count steps by counting loops: sequential loops add (still linear); nested loops over the same input multiply (quadratic).
# Chef A β one pass: n steps
for guest in guests:
prep(guest)
# Chef B β all pairs: ~n*n/2 steps. Alarm bells!
for a in guests:
for b in guests:
if a != b and a.email == b.email:
print("duplicate!")
# The escape (Module 2 preview): one pass + a set
seen = set()
for g in guests:
if g.email in seen: print("duplicate!")
seen.add(g.email)