Define
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.
size="S" gives size a default. Python works out 'S' once, when the def line runs, and keeps it with the function. Any call that leaves size out will get 'S'.
Call
Line 3 calls order("tea"); "tea" is an argument, a value passed in a call. Each call gets a fresh frame: one box per parameter. Unnamed arguments are positional: they fill parameters left to right, so 'tea' goes into drink.
No second argument, so size takes its default, 'S'. Nothing is left over: extras is an empty tuple, (), and notes an empty dict, {}. Line 2 prints: tea S () {}
size="L" passes an argument by name: a keyword argument. It goes straight to the parameter called size and replaces the default for this call only. 'tea' still fills drink by position. Line 2 prints: tea L () {}
Line 5 passes four positional arguments and one keyword. The first two fill drink and size, in order: 'latte' and 'L'. Only their position decides where they go, not what they mean.
Pack the rest
'oat' and 'honey' are left over: every named parameter is full. The star in *extras packs all extra positional arguments into one tuple, ('oat', 'honey'). The usual name is *args; any name works.
shot=2 matches no parameter name. The two stars in **notes gather every such keyword argument into a dict, {'shot': 2}, usually called **kwargs. Line 2 prints: latte L ('oat', 'honey') {'shot': 2}
Rules
Call order() with nothing and drink stays empty: it has no default, so it is required. Python stops before the body runs: TypeError: order() missing 1 required positional argument: 'drink'.
In def, a parameter with a default can't be followed by one without a default (before *extras), and **notes must come last. In a call, positional arguments come before keyword ones. Break either rule and Python reports a SyntaxError.
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.