A vending machine with a private kitchen

Functions & Scope

The analogy

A function is a vending machine: you put coins in the slot (arguments), something happens inside that you cannot see, and a snack drops out (the return value). Write the recipe once, press the button a thousand times. Scope is the machine's private kitchen: variables created inside the function live ONLY inside it โ€” the kitchen's mess never leaks into the shop, and two machines can both have a bowl called "mix" without fighting. When a function runs, the machine goes onto a stack of "machines currently working"; when it returns, it is lifted off and its whole kitchen is thrown away. That stack of working machines is the call stack โ€” remember the tray-pile stack from Module 2? Same object. And a machine that presses its own button is recursion, waiting for you at the end of Module 3.

Visualizer

Machines on the stack

step 1 / 6
bottom
main() โ† top

The program itself is a machine already running โ€” the bottom of the pile.call stack, depth 1

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

Scope resolution โ€” LEGB

layermeaningexample
L โ€” Localinside the current functionthe tax in price_with_tax
E โ€” Enclosingthe function wrapping this oneclosures read the outer function's names
G โ€” Globalmodule top levelconstants, imports
B โ€” Built-inprint, len, rangeโ€ฆshadowable โ€” naming a variable `list` breaks list()

The rules

  • Assignment inside a function creates a LOCAL, even if the name exists globally โ€” reading falls through LEGB, writing does not. `global`/`nonlocal` override (and are usually a design smell).
  • Default parameter values are evaluated ONCE at def time: def f(acc=[]) shares one list across every call. Use None + create inside โ€” the most famous Python bug.
  • Arguments pass object references: rebinding a parameter does nothing outside; MUTATING a passed list is visible outside.
  • return ends the call immediately; a function without return returns None.
  • Each call gets a fresh frame on the call stack (~depth limit 1000 โ€” sys.setrecursionlimit); frames die at return, taking their locals with them.
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 gone
Check yourself

x = 10. def f(): x = 5. Call f(). What is x now, outside?

Practice โ€” write it yourself

price_with_tax(price, rate) returns price + price*rate, rounded to 2 decimals (round(x * 100) / 100). Keep everything local; just return.

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