QuestenaPractice that shows what to review next
Topic lesson

Functions: separate definition, binding and execution

About 6 min

Questions stay in the language in which they were published.

These questions ask what happens when a function is defined, called and completed. Keep those stages separate, then trace argument evaluation, parameter binding and the returned result in that order.

Follow the function lifecycle

At definition time, Python executes def, creates a function object and binds its name; the body does not run yet. In def twice(n): return n * 2, twice becomes a reference to that function. Functions are ordinary objects, so another name can store one, a call can receive one, and a function can return one. A lambda also creates a function, but its body is one expression whose value is returned implicitly, as in lambda n: n + 1.

At call time, evaluate every argument expression from left to right before entering the body. Then bind each result by position or by an allowed parameter name. A parameter cannot receive two values in one call. Binding shares the argument object rather than copying it, so def add(items): items.append(9) can mutate a list supplied by its caller. An executed return ends only the current call; if control reaches the end without one, the result is None.

Parameter formBinding method
An ordinary parameterFill it once by position or by its permitted name.
A parameter after a bare star or a starred positional collectorSupply it by name; additional positional values cannot fill it.
A starred positional collectorGather unmatched positional values into a tuple, as def pack(*items): return items does.
A double-starred named collectorGather unmatched named values into a dictionary, as a function whose parameter is written with a doubled star, collecting the extras into a dictionary does.

Defaults belong to definition time too: the expression is evaluated once when def executes, and later omitted arguments reuse that resulting object. Inside a function, assigning to a name normally makes that name local unless a global or nonlocal declaration changes the rule. Decide scope from the function body, not from which branch happens to run.

Reject these tempting routes

Tempting routeHow to reject it
Run the body when def is encountered, or postpone creation until the first callDefinition creates and names the function; invocation is the separate event that enters its body.
Assume calls deep-copy mutable argumentsTrack object identity through binding. Mutation through the parameter is visible through every reference to that object.
Infer a result from the final local name when return is absentOnly an executed return supplies an explicit result. Reaching the end produces None.
Recompute a default expression on every omitted callAttach the resulting default object to the definition event and reuse it when the argument is absent.
Collect starred positional values in a list or named values in a tupleMatch the marker to its container: one star gathers a tuple; two stars gather a dictionary.
Let a marker affect earlier parameters, or forbid defaults on later named parametersThe marker changes following parameters only, and those parameters may still declare defaults.

Try it

Question 74

Assume total is a defined ordinary function that accepts these arguments, and count and value are defined and both return normally. For total(count(), text=value()), which evaluation statements are true? Select all that apply.

  1. The expressions wait and run lazily inside total.
  2. Both argument expressions finish before total starts.
  3. The keyword expression must run before every positional expression.
  4. count() is evaluated before value().
Question 77

Given def total(count, text): pass, what happens when total(1, count=2, text="x") is called?

  1. count becomes 2 because the keyword overrides 1.
  2. It raises TypeError because count receives two values.
  3. It succeeds only because text is supplied last.
  4. It raises ValueError because keyword order is wrong.
Question 82

Inside a function body, count is assigned without any global or nonlocal declaration. How does Python normally classify count in that function?

  1. It automatically updates a same-named global.
  2. It is local to the function by default.
  3. Its scope is chosen after the function returns.
  4. It is local only when its value is mutable.
Start drillPractice this topic
Functions: separate definition, binding and execution · Questena