def, return, None, and Call Flow
Key Takeaways
- A def statement creates a function object at definition time; the indented body does not run until the function is actually called.
- A function that reaches the end of its body without executing a return statement returns None implicitly.
- print() displays text on standard output and itself evaluates to None, while return sends a value back to the caller.
- Once a return statement executes, the current function call ends and any later statements on that path are skipped.
- Nested function calls are resolved innermost-first; the inner return value becomes the outer call's argument.
Why call flow matters on PCEP
The PCEP-30-02 exam asks 30 questions in 40 minutes (about 80 seconds each, 70% to pass). Functions-and-exceptions items rarely ask you to write code; they show a short snippet and ask what it prints, returns, or raises. To answer fast and correctly, separate three distinct moments: Python reads the def statement, the program calls the function, and the caller uses whatever value comes back.
A def statement binds a name to a function object. The indented body is compiled and stored, not executed. The body runs only when the name is followed by parentheses with the required arguments.
def double(n):
print('inside')
return n * 2
print('before')
value = double(4)
print(value)
The output is before, then inside, then 8. Defining double printed nothing. The assignment value = double(4) receives the return value 8; it does not receive the word printed inside the body.
return versus print: the most-tested distinction
| Feature | print() | return |
|---|---|---|
| Main job | Writes text to standard output | Sends a value back to the caller |
| Value of the expression | Always None | The returned object |
| Can be stored/combined | No (you store None) | Yes |
| Ends the function call | No | Yes, immediately |
| Common PCEP trap | Assuming printed text is "the result" | Code after return is silently skipped |
A function may both print and return in one call, but the actions are unrelated. If a question asks for output, count only printed text. If it asks for the value assigned to a variable, follow the return value.
def label(x):
print('item', x)
result = label(3)
print(result)
This prints item 3 and then None. label has no return statement, so when the body ends Python supplies None automatically, and that None is what result stores.
Three ways a function returns None
There are exactly three common paths to an implicit or explicit None:
- The function has no return statement at all.
- The function executes a bare
returnwith no expression after it. - Execution falls through a branch where no return is reached.
def sign(n):
if n > 0:
return 'positive'
if n == 0:
return
print(sign(5))
print(sign(0))
print(sign(-2))
The three calls print positive, None, and None. The zero call hits a bare return; the negative call runs off the end of the body. Both yield None by different routes, and PCEP loves to mix the two in one snippet.
Reading nested calls
When calls are nested, resolve the innermost call first, then pass its return value outward.
def add_one(n):
return n + 1
def show(n):
print(n)
return n * 10
answer = show(add_one(2))
First add_one(2) returns 3. Then show(3) prints 3 and returns 30. Finally answer becomes 30. Note a name without parentheses is just a reference: tool = show runs no body, while tool(3) does.
A repeatable exam tracing routine
Use this checklist on every function snippet so you never confuse output, function objects, and return values:
- Mark every
defas a definition only; do not execute its body yet. - Find the first actual call at the top level.
- Bind arguments to parameters for that call.
- Trace the body until a
return, an exception, or the natural end. - Replace the entire call expression with the value it returned.
- Continue at the line after the call.
Worked trap. Consider x = print('hi'). Many candidates pick 'hi' as the value of x. Wrong: print displays hi but evaluates to None, so x is None. Then print(x + 1) would raise TypeError because None + 1 is invalid. Recognizing that print returns None is worth several marks across the exam.
The routine is slower than guessing but far faster than rereading a snippet three times. On PCEP, the difference between definition and call, and between print and return, is frequently the entire question.
More patterns the exam reuses
A few additional behaviors of call flow show up repeatedly and are worth drilling until automatic.
A function object is a first-class value. You can store it, pass it, and call it later. The presence or absence of parentheses is the whole difference between referencing and calling. In funcs = [double], no body runs; funcs[0](5) is what finally calls it. PCEP often plants a bare function name in a list or assignment to see whether you mistake the reference for a call result.
Multiple return values are really one tuple. Writing return a, b returns a single tuple (a, b). The caller can unpack it with x, y = f(). If a snippet stores the result in one variable, that variable holds the whole tuple, not just the first item.
A return inside a loop exits the entire function, not just the loop. Compare with break, which only leaves the loop and lets later statements run:
def first_even(nums):
for n in nums:
if n % 2 == 0:
return n
return None
print(first_even([1, 3, 4, 7]))
This returns 4 the instant the loop finds an even number; the loop and the function both end, and the trailing return None never runs. Whenever you see a return inside a loop, stop tracing the loop the moment it fires.
Quick contrast table:
| Statement | Leaves loop? | Leaves function? |
|---|---|---|
break | Yes | No |
continue | No (skips to next iteration) | No |
return | Yes | Yes |
Keeping these three apart prevents the classic mistake of thinking code after a return-in-a-loop still executes.
A Python function finishes executing its body without ever reaching a return statement. What value does the call evaluate to?
Why does print() behave differently from return in a PCEP output question?
Given the body return 2 followed by print(3) on the next line, what happens to print(3) when the function is called?