Concepts / Defining and Calling User-Defined Functions

Defining and Calling User-Defined Functions

Expressions and variables can both be passed as arguments to user-defined functions, just as they can be passed to built-in functions.

  • Programming

The Value Before the Function

When you call a function, the information inside the parentheses is an argument. That argument may be a literal value, a variable, or an expression such as a calculation or another function call. User-defined functions accept these forms in the same way built-in functions do. The important question is not only what appears in the call, but what value Python has prepared before the function begins running.

Tracing an Expression Argument

What do you think happens?

What does the user-defined function receive when it is called with 'Spam ' * 4?

  • The expression 'Spam ' * 4
  • The resulting repeated string
  • Four separate arguments
Reveal answer

Answer: The resulting repeated string: 'Spam Spam Spam Spam '.

Python evaluates the expression once before the function is called. The resulting single string is passed to the function, whose parameter then holds that string.

evaluatepass resultbind valueCaller'Spam ' * 4expressionprint_twicefunction callbruce'Spam Spam Spam Spam '
What happens to the expression 'Spam ' * 4 before the function body starts running?

The sequence has three important stages. First, Python computes the expression. Second, it calls the user-defined function with the resulting value. Third, the function's parameter holds that value while the function body runs. The string repetition happens once during the first stage, even if the function later prints the received string twice.

python
Output
Spam Spam Spam Spam 
Spam Spam Spam Spam 

What a Parameter Receives

An expression is a combination of values, operators, and function calls that Python can evaluate to produce a result. When an expression is used as an argument, the expression is evaluated first and only its result is passed to the function.

A variable works differently in appearance but not in timing. When a variable is passed, Python looks up the value stored in that variable. The function receives that value, not the variable name. Thus, a parameter can receive a string retrieved from a variable just as it can receive a string produced by an expression.

retrieve stored valueevaluate oncepass resultmichael'Eric, the half a bee.'argument valueone evaluated valuebrucevalue received by functionmath.cos(math.pi)-1.0
How does a value from a variable or an expression move into the function's parameter?
Argument formWhat Python does before the callWhat the function receives
VariableLooks up the value stored in the variableThe stored value
ExpressionEvaluates the expression onceThe expression's result

Two Calls, Two Preparation Steps

Comparing a Variable with an Expression

Determine what print_twice receives in each call: print_twice(michael) and print_twice(math.cos(math.pi)).

Variable call: The variable michael stores the string 'Eric, the half a bee.'. Python retrieves that stored string and passes it to print_twice.

Expression call: The expression math.cos(math.pi) is evaluated once before print_twice is called. Its result is -1.0, so -1.0 is passed to the function.

Function execution: In each case, the parameter bruce holds the received value. The function uses that value when it runs.

The first call receives 'Eric, the half a bee.'. The second call receives -1.0. The function receives values, not the variable name or the unevaluated expression.

python
Output
Eric, the half a bee.
Eric, the half a bee.
-1.0
-1.0

Although the function prints each received value twice, that repetition is part of the function's behavior. It does not mean that the argument preparation happened twice. The expression math.cos(math.pi) was called once, before the function began.

Debugging the Evaluation Boundary

When a user-defined function behaves unexpectedly, separate argument preparation from function execution. First identify whether the call uses a variable or an expression. For a variable, check the value currently stored in it. For an expression, check whether the expression produces the value you expect. Then check how the function uses the value it receives. This trace shows whether the problem occurred before the call or inside the function.

  1. Identify the argument in the function call.
  2. If it is a variable, determine the value stored in that variable.
  3. If it is an expression, evaluate the expression once.
  4. Record the value that reaches the function parameter.
  5. Trace how the function uses that received value.

Mistakes in Argument Tracing

  • Assuming the function receives the variable name

    Python looks up the value stored in michael and passes that value to the function.

    Fix: Trace michael to its stored string value before reasoning about the function body.

  • Assuming an expression is evaluated inside the function

    The expression is evaluated once before the function is called.

    Fix: Write down the expression's result first, then use that result as the function's input.

  • Counting repeated use inside the function as repeated argument evaluation

    The expression is computed once before the call. The function can then use the resulting value more than once.

    Fix: Keep the argument-evaluation step separate from the later actions performed by the function.

Practice the Trace

MEDIUM

For each call, state the exact value that reaches the function parameter before the function body runs: print_twice('Spam ' * 4), print_twice(michael), and print_twice(math.cos(math.pi)). Then state whether the value came from a variable lookup or expression evaluation.

Hints
  • An expression contributes its result, not the expression itself.
  • A variable contributes the value stored in it, not the variable name.
  • The argument is prepared before the function is called.

Practice Check

Predict the value received by print_twice in the call print_twice(math.cos(math.pi)).

Identify the argument: The argument is the expression math.cos(math.pi), not a variable.

Evaluate once: The expression produces -1.0 before the function is called.

Pass the result: The function receives -1.0 as the value of its parameter.

The function receives -1.0. If the function prints its parameter twice, the output contains -1.0 twice.

Key Takeaways

  1. User-defined functions can receive literals, variables, and expressions as arguments.
  2. Python evaluates an argument exactly once before calling the function.
  3. A variable argument contributes the value stored in the variable, not its name.
  4. An expression argument contributes the result of evaluating the expression, not the expression itself.
  5. Tracing the value from the call to the parameter helps separate argument-preparation problems from function-body problems.

Key Takeaways

  • Expressions and variables can both be passed to user-defined functions.
  • Arguments are evaluated exactly once before the function is called.
  • A function receives an argument's value, not a variable name or an unevaluated expression.
  • Tracing evaluation makes function output easier to predict and unexpected behavior easier to debug.