1.2.27 · D5Introduction to Programming (Python)
Question bank — Functions — def, parameters, return, docstrings
Before we start, three words we'll lean on — defined in plain speech so nothing is assumed:
True or false — justify
Each answer explains why, because a bare "true/false" teaches nothing.
Defining a function with def also runs its body once.
False.
def only builds the function object and binds the name; the body runs only when you call it with parentheses — see Variables and Scope for why the body's names don't even exist until then.print(x) and return x do the same thing because both make x appear.
False.
print sends text to the screen for a human and the function still returns None; return hands the value back to the program so later code can use it. Only one is usable in y = f().A function must have a return statement to be valid Python.
False. A function with no
return is perfectly valid; it just returns None automatically. Many useful functions (that only print or modify a list) never return.return a, b returns two separate values.
False. It returns one object — a tuple
(a, b) — which you then unpack with x, y = f(). See Lists and Tuples for tuple packing.greet and greet() mean the same thing.
False.
greet is the function object itself (the machine sitting on the shelf); greet() calls it (presses the button). Passing greet without () is how Lambda and Higher-order Functions hand functions around.In def add(a, b), the a and b are arguments.
False. They are parameters — the empty slots. The arguments are the real values (like
2 and 3) you supply at call time.Two functions named the same in one file both stay usable.
False. The second
def rebinds the name, silently replacing the first — the first becomes unreachable. Names are just labels, and a label points to one thing.def f(exp=2, base): is a legal header.
False. A parameter with a default may never come before a parameter without one; Python raises a
SyntaxError. Required slots must appear first.Writing a docstring changes what the function returns.
False. A docstring is just documentation stored on the function; it has zero effect on the returned value. It's readable via
help() and never alters behaviour.Spot the error
Say what's wrong and how you'd feel misled.
def square(n):
print(n * n)
y = square(5)Why is y not 25?
square uses print, not return, so it displays 25 but hands back nothing — y becomes None. The screen output looks like success, which is the trap.def add(a, b):
return a + b
print("done")Why does "done" never appear?
return exits the function immediately, so any code after it on that path is dead. The line is silently unreachable.def collect(item, bag=[]):
bag.append(item)
return bagWhy does bag remember old items across calls?
The default
[] is created once at definition time and shared by every call that omits bag, so it accumulates. The fix is a None sentinel: default to None, then set bag = [] inside.def greet(name):
"""Greet someone."""
greet("Sam")What does this call give back, and is that a bug?
It returns
None (no return), which is fine if you only wanted a side effect — but here there's no print either, so it does literally nothing visible. The empty body is the real problem.def power(base, exp=2)
return base ** expSpot the syntax slip.
The header is missing its colon
:. Python needs def power(base, exp=2): to know the header ended and the block begins.def f():
x = 10
print(x)Why does print(x) fail?
x lives only inside f's own scope; it doesn't exist outside. This is Variables and Scope — locals are isolated, giving a NameError outside.def divide(a, b):
return a / b
q, r = divide(17, 5)Why does the unpacking fail?
divide returns a single float, not two values, so q, r = ... can't split it into a pair. You'd need return a // b, a % b to get an unpackable tuple.Why questions
Push past what into why it's designed that way.
Why do functions exist at all if you could just copy-paste the code?
To honour the DRY Principle — write logic once so a fix happens in one place. Copy-paste means changing the formula in 12 spots and missing one.
Why does return both send a value and stop the function, rather than just sending it?
Because once the answer is ready, continuing would waste work or overwrite it. Stopping guarantees exactly one answer leaves per path — this also powers early exits inside Control Flow — if statements.
Why distinguish "parameter" from "argument" if they hold the same thing?
They describe two different moments: the parameter is the empty slot fixed at definition, the argument is the filling supplied at each call. One definition, infinitely many argument sets.
Why can you call a function by keyword (power(exp=3, base=2)) instead of by position?
Keywords bind values by name, so order stops mattering and the call self-documents. It's a readability tool for functions with many parameters.
Why is a docstring placed inside the function instead of as a comment above it?
Because Python stores the first string literal as the function's official documentation, retrievable at runtime via
help(). A # comment is invisible to help().Why does a bare return (with nothing after it) even exist?
To exit early without producing a value — useful inside an
if to bail out. It still returns None, just sooner.Why is a function that calls itself (Recursion) even possible?
Because
def only binds a name; by the time the body runs (at call time) that name already points to the function, so it can reference itself.Edge cases
The boundary and degenerate situations that surprise people.
What does a function with an empty body (def f(): pass) return?
None. No return means the automatic "nothing" object comes back, even though nothing happened inside.What does x, y = f() do if f returns None?
It raises a
TypeError — None can't be unpacked into two names. This is the common downstream symptom of forgetting a return.If a function has return inside an if but the condition is false, what comes back?
None, because that path reaches the end of the body without hitting a return. Every path should return deliberately, or you get surprise Nones.Can you call a function before its def line appears in the file?
Not at module top level — the name isn't bound until the
def executes. But a call inside another function's body is fine, since that body runs later, after all defs have run.What happens if you pass more arguments than there are parameters?
A
TypeError — Python counts slots and refuses a mismatch. Extra flexibility needs *args, which is beyond this core.Does return a, b, c build a tuple even without parentheses?
Yes — the commas make the tuple, not the brackets.
(a, b, c) and a, b, c are the same object here (see Lists and Tuples).If two parameters have defaults and you supply only one positional argument, which slot gets filled?
The first parameter, by position; the rest fall back to their defaults. Position always fills left-to-right before defaults kick in.
Recall One-line self-check
A function that only prints and never returns — what is its return value? ::: None, always.
Connections
- Variables and Scope — why a function's locals vanish outside it.
- Control Flow — if statements — where early
returns and surpriseNones come from. - Lists and Tuples — the tuple behind
return a, b. - Recursion — why a function can name itself.
- Lambda and Higher-order Functions — passing
greetwithout(). - DRY Principle — the reason functions exist.