Concepts / Side Effects vs. Return Values

Side Effects vs. Return Values

Void functions perform actions but return None, not a usable value.

  • Programming
Interactive lab

Try it: Defining and Calling Functions

What def and a call really do: def only creates a function object, a call binds the arguments to the parameters in a new frame and runs the body, return ends the call at once and its value replaces the call expression in the caller — while a function that only prints gives back None.

How it works

  1. def name(params): creates a function object and binds the name to it; the body does not run yet.
  2. A call evaluates its arguments, opens a new frame, binds each parameter to its argument and runs the body from the top.
  3. return value ends the call immediately (lines after it never run) and sends the value back; the frame and its local names are discarded.
  4. In the caller, the call expression is replaced by the returned value, which can be stored, used in a larger expression or passed to another call.
  5. A body that ends without return (e.g. one that only prints) makes the call evaluate to None — so x = f() stores None and None + 1 raises TypeError.
  6. Calling a name before its def has run raises NameError: the function does not exist yet.

Default run (18 steps): The program is ready. Python runs it from the top, one statement at a time. Idea: the value a call returns is what the caller stores. … The program finished. Console: 8.

Simplified: Four fixed, hand-written programs; you edit the literal arguments, switch the body between return and print, and move the def after the calls. The lab's own small evaluator runs them (your input is never executed as code); every variant was run in CPython 3.12 and the lab reproduces its sys.settrace line/call/return/exception events, its output and its error message. Functions are shown as <function name> without a memory address.

Educational simulation

Loading the simulation…

The Visible Action Trap

Many learners expect every function call to produce a value that can be stored and reused. That expectation seems reasonable when a call visibly does something. For example, print displays text on the screen. However, the action performed by a function and the value returned to its caller are separate things. A function can perform a visible action while returning no usable value.

What do you think happens?

What do you think result contains after the function call performs its printing action?

  • The text that was printed

  • None

  • The string 'None'

Reveal answer
Answer:

None

The printing action happens on the screen, but the function does not provide a usable return value. Python represents that absence with the special value None.

CallerVoid functionperforms an actionScreen outputNoneno usable valueFruitful functionreturns a valueUsable valuecallscausesreturnscallsreturns
How does data or control flow differ when a function performs an action versus when it returns a value?

Two Kinds of Function Results

Definition

A void function performs an action, often a side effect such as printing, but returns None rather than a usable value. A fruitful function computes and returns a meaningful value that the caller can store and use in later calculations.

Function kindWhat happens when it runsWhat the caller receives
Void functionIt performs an action or side effectNone
Fruitful functionIt computes a resultA meaningful value

The action performed by a function is separate from the value it returns.

The distinction is not whether the function call appears to do something. A void function may clearly change what you see on the screen or perform another action. The distinction is whether the caller receives a meaningful value for storage, calculation, or another operation.

Code walkthrough
def print_twice(text):
    print(text)
    print(text)

result = print_twice('Bing')
print(result)
  1. 1
    First, print_twice('Bing') is called.
  2. 2
    Next, 'Bing' appears twice as the function performs its action.
  3. 3
    Then the result of the call is assigned to result.
  4. 4
    Finally, print(result) displays None.
  • The function performs its printing action twice.
  • The call produces screen output before assignment finishes.
  • The variable receives None because the function does not return a usable value.
  • Printing the variable displays None.
Output
Bing
Bing
None

Assignment Stores None

Assignment does not capture everything a function does. It captures the value produced by the function call. In the print_twice example, the two lines of screen output are the side effect. The value assigned to result is None. The sequence is therefore: call the function, observe its action, assign its returned value, and then observe None when the variable is displayed.

resultnot assignedprint_twiceprints 'Bing' twiceresultNoneassignment evaluates callstores returned value
What value is placed in a variable after assigning the result of a function that has no usable return value?
Worked example

Tracing a Void Function Assignment

Determine what happens when the result of an action-oriented function is assigned to a variable.

  1. 1
    Call

    The function is called and performs its action by printing the text twice.

  2. 2
    Return

    The function does not provide a usable value, so Python represents the absence of that value as None.

  3. 3
    Assignment

    The variable receives the function call's result, so the variable contains None rather than the printed text.

  4. 4
    Later use

    Displaying the variable shows None. The screen output and the returned value were separate results.

Result

The function performs its action, but the assigned variable contains None.

What None Means

None is a special Python value with its own type, NoneType. It is not merely an empty slot, and it is not the text string 'None'. The two may look similar when displayed, but they represent different things. None signals that a function did not produce a usable value for its caller, while 'None' is text.

ItemMeaningType
NoneA special value representing no usable return valueNoneType
'None'Text containing the characters N, o, n, eString

Similar spelling does not make None and 'None' the same value.

NoneNoneType'None'string
What is the difference between the special value None and the text string 'None'?

Tracing an Unexpected None

A None-related bug usually begins with an incorrect expectation about the function's result. The caller expects a meaningful value, but the function is void or reaches a path that does not provide one. Trace the call from the caller into the function, identify the action it performs, and then check what value reaches the assignment. If that value is None, the function did not produce the result the caller needs.

Function callFunction actionrunsExpected valueprovided?Meaningful valuecaller can use itNonecaller received no usablevalueentersthen check resultyesno
At which point in the function's control flow does the expected value fail to be returned, causing None to reach the caller?
  • Common mistake

    Assuming visible output is the function's return value

    What it looks like

    A function prints text, so the caller assumes the assigned variable contains that text.

    Why it fails

    Printing is an action or side effect. The function can perform that action and still return None.

    Do this instead

    Trace the value returned by the call separately from what appears on the screen.

  • Common mistake

    Using a variable containing None in a calculation

    What it looks like

    A variable receives the result of a void function and is then treated as a number.

    Why it fails

    None is not a usable calculation result.

    Do this instead

    Identify whether the called function is fruitful before using its result in a calculation.

  • Common mistake

    Confusing None with the string 'None'

    What it looks like

    Code treats None and 'None' as interchangeable because they look similar when displayed.

    Why it fails

    None has type NoneType, while 'None' is text.

    Do this instead

    Keep the special value None conceptually separate from the string 'None'.

Practice the Distinction

EASY

A function call produces visible output, and its result is assigned to a variable. Explain separately what the function did as an action and what value the variable received. Then classify the function as void or fruitful and explain why.

Hints
  • Do not treat screen output and a returned value as the same result.
  • Ask whether the caller received a meaningful value that can be used later.
  • If the function did not return a usable value, identify the special value Python uses.
MEDIUM

You expected a variable to contain a value for a calculation, but debugging shows that it contains None. What should you inspect first: the screen output, the function's action, or the value returned to the caller? Explain your choice.

Hints
  • The bug concerns the value assigned to the variable.
  • A function can complete an action without returning a usable value.
  • Trace the function call and identify whether it is void or fruitful.

Key Takeaways

  1. 1
    A void function performs an action but returns None rather than a usable value.
  2. 2
    A fruitful function returns a meaningful value that the caller can store and use.
  3. 3
    Assigning the result of a void function stores None in the variable.
  4. 4
    None is a real Python value of type NoneType, not the string 'None'.
  5. 5
    When an expected value becomes None, trace the function call and check whether the function actually returns a usable result.

At a glance

  • Side effects describe what a function does; return values describe what the caller receives.
  • Void functions return None, even when their actions are visible.
  • Fruitful functions return meaningful values that can be stored and used.
  • None and the string 'None' are different, and None has type NoneType.
  • An unexpected None is a debugging clue that the caller did not receive the value it expected.

Related concepts

More concepts starting with S