drinksize*extras**notesorder()1def order(drink, size="S", *extras, **notes):2 print(drink, size, extras, notes)3order("tea")4order("tea", size="L")5order("latte", "L", "oat", "honey", shot=2)order()size defaultTypeError'S''tea''S''L''tea''latte''L''oat''honey'shot=2
Code card: order.py; the highlighted line is the one runningFunction order(): its default value 'S' waits in the khaki boxFrame: one box per parameter, filled fresh by every callTokens: the argument values on their way into the boxesA call hands values to a function's parameters. Positional arguments fill them left to right, keyword arguments go to the parameter they name, and a parameter nobody fills takes its default. Each step lights the parts it is about. Value tokens hop from a call's line into the boxes of the call's frame; the leftovers are packed into the tuple *extras and the unknown keyword into the dict **notes. In the error step line 3 becomes order(): drink has no default, so Python raises a TypeError before the body runs.

Define

  1. Line 1, def order(...):, creates a function named order. The names in brackets are its parameters: drink, size, extras and notes. The indented line 2 is the body: it runs on every call and prints the four values.

Call

Pack the rest

Rules

Try it yourself

;; step 1/10 · line 1: def order(drink, size="S", *extras, **notes):
def order(drink, size="S", *extras, **notes):
    print(drink, size, extras, notes)

>>> type(order)
<class 'function'>

Python binds every argument of a call at the same moment, before the body on line 2 runs; the figure shows them one group at a time so each rule can be seen on its own. A default is evaluated once, when def runs, and then shared by every call. That is why a list default such as [] keeps growing between calls: use None and make the list inside the function instead.