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.

Caller'Spam ' * 4expressionprint_twicefunction callbruce'Spam Spam Spam Spam 'evaluatepass resultbind value
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

Definition

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.

michael'Eric, the half a bee.'argument valueone evaluated valuebrucevalue received by functionmath.cos(math.pi)-1.0retrieve stored valueevaluate oncepass result
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

Both forms provide a value to the function; the preparation step differs.

Two Calls, Two Preparation Steps

Worked example

Comparing a Variable with an Expression

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

  1. 1
    Variable call

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

  2. 2
    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.

  3. 3
    Function execution

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

Result

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

Mistakes in Argument Tracing

  • Common mistake

    Assuming the function receives the variable name

    What it looks like

    Calling print_twice(michael) and reasoning that the parameter receives the name michael

    Why it fails

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

    Do this instead

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

  • Common mistake

    Assuming an expression is evaluated inside the function

    What it looks like

    Treating math.cos(math.pi) as if the function receives the unevaluated expression

    Why it fails

    The expression is evaluated once before the function is called.

    Do this instead

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

  • Common mistake

    Counting repeated use inside the function as repeated argument evaluation

    What it looks like

    Concluding that 'Spam ' * 4 runs twice because the function prints its parameter twice

    Why it fails

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

    Do this instead

    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.
Worked example

Practice Check

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

  1. 1
    Identify the argument

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

  2. 2
    Evaluate once

    The expression produces -1.0 before the function is called.

  3. 3
    Pass the result

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

Result

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

Key Takeaways

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

At a glance

  • 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.

Related concepts

More concepts starting with D