P2-8.5 Functions and Small-Scale Reuse¶
Section ID:
P2-8.5Version:v2026.09.15
Defining and Calling Functions¶
A function generally receives input, performs processing, and returns a result. Mathematics emphasizes the input-output relationship; programming expresses it as executable code.
Python uses def to name a function and parameters to name its inputs.
Score 82 meets the threshold 60, so pass is printed. This version uses a conditional without a function.
For a single decision, this may be enough. Repeating the same decision for many scores, however, duplicates code.
Naming the decision pass_or_fail lets callers vary only the score. The outputs below are pass and fail.
pass_or_fail is the function name, and score names its input. return sends the result back to the call site and ends the current call. With 82, it returns "pass" and never reaches return "fail".
Mathematical Functions and Python Functions¶
In mathematics, functions are usually described through input-output relationships.
The mathematical function \(f(x)=x+1\) can be implemented as follows. Passing argument 3 prints 4.
| Aspect | Mathematical function | Python function |
|---|---|---|
| Main focus | Input-output relationship | Executed code and results |
| Notation | \(f(x) = x + 1\) | def f(x): return x + 1 |
| Side effects | Usually treated as a pure relationship | Can print, save files, or change lists |
| Errors | Inputs outside the domain are treated mathematically | Can raise type, key, or execution errors |
AI exercises need both perspectives.
- Understand loss functions as mathematical relationships.
- Use Python functions to reuse those calculations as code.
- Use library functions through their input-output contracts without knowing every implementation detail.
Parameters and Arguments¶
A parameter names an input in a function definition. An argument is the value supplied when calling it.
Adding bonus 5 to score 80 returns 85. The definition uses parameters score and bonus; the call supplies arguments 80 and 5.
| Term | Location | Example |
|---|---|---|
| Parameter | Input name in the definition | score, bonus |
| Argument | Actual value at the call | 80, 5 |
| Return value | Result sent back by the function | 85 |
Returning and Printing¶
return sends the function's computed result back to its call site.
Divide score 82 out of 100 by 100 and return the result. The caller stores 0.82 in normalized and prints it.
normalize_score(82) returns 0.82, which is assigned the name normalized.
print() and return are different operations.
show_score(82) prints 82. Without a return, however, it returns None, so print(result) prints None.
A function reaching its end without return returns None. The displayed 82 is not stored in result. Computing result + 1 raises TypeError, because None cannot be added to an integer.
Reusing Repeated Calculations¶
Giving a repeated calculation a name exposes its intent.
Applying normalize_score() to four scores prints [0.82, 0.75, 0.91, 0.68]. The loop retrieves scores; the function divides each by 100.
A simple expression does not always need a function. Functions help when the calculation appears in multiple places or a name makes its purpose clearer.
Processing One Sample¶
AI exercises often use functions that process one sample.
Check whether both "text" and "label" keys exist. This input contains both, so the code prints True.
This checks key presence only. {"text": "", "label": None} also returns True. It does not check for empty text or an allowed label value.
The same function can process multiple samples.
Apply the key check to three samples. The second lacks "label", so only the first and third dictionaries remain in the result list.
Default Parameter Values¶
Function parameters can have default values.
With the default threshold 60, score 82 returns pass; with threshold=90, it returns fail. Only the threshold differs between these calls.
The first call omits a threshold, so it uses 60. The second supplies threshold=90 explicitly.
AI tools and libraries commonly use this form.
batch_size=32learning_rate=0.001shuffle=Truemax_tokens=100
Defaults are convenient, but assuming the wrong default leads to misunderstandings. Check the defaults in library documentation.
Passing Function Objects¶
Python functions are objects, and function names refer to those objects.
normalize = normalize_score adds another name for the function object. normalize(82) also prints 0.82.
normalize does not define a new calculation; it refers to normalize_score under another name. Distinguish the function object normalize_score from its call result normalize_score(82).
Pass scores [82, 75, 91] together with normalize_score. apply_to_scores() applies that function to each score and returns [0.82, 0.75, 0.91]; the outer print() displays it.
apply_to_scores() receives both the list and the function. At function(score), it calls the supplied function for the current score.
This pattern appears throughout data processing and AI libraries.
- Pass a function as a sorting key.
- Pass preprocessing functions to repeated processing.
- Pass metric functions to training code.
- Use callbacks to specify actions at particular times.
Functions and Methods¶
function(value) calls a function by name; value.method() retrieves and calls a method on an object.
A function is an independently defined processing unit. A method looks like a function called through an associated object.
Apply whitespace removal and lowercasing to " AI is Useful ". clean_text(text) prints ai is useful, text.strip() prints AI is Useful, and text.lower() prints ai is useful with surrounding spaces intact.
clean_text(text) is an independent function call; strip() and lower() are methods provided by strings. Methods also use parentheses, but the target object appears before the method name.
| Form | Introductory explanation | Example |
|---|---|---|
| Function | Named independent processing unit | clean_text(text) |
| Method | Function-like operation called through an object | text.strip() |
Separating Processing Steps¶
Small functions make inputs, processing, and outputs clear. A function doing too many jobs obscures its responsibilities.
For example, suppose one function performs all these tasks:
- Read a file.
- Remove empty rows.
- Convert scores to numbers.
- Calculate the mean.
- Save the result.
Such a function may look simple, yet changing just one part later can be difficult.
Case: Removing Empty Text After Trimming¶
Clean [" AI is Useful ", "", " Models can FAIL "], then remove empty strings. The output is ['ai is useful', 'models can fail'].
clean_text() cleans one string; is_not_empty() checks whether characters remain. Adding " " to the input leaves the output unchanged because trimming makes it empty. Checking emptiness before cleaning would accept that length-3 string. Call order affects the result.
Case: Changing the Maximum Score¶
Suppose division by 100 was copied into two places, then the exam maximum changed to 50. Updating only one place to / 50 makes score 40 become 0.8 in one place and 0.4 in the other.
Accepting the maximum as a parameter lets callers pass both score and maximum to one function. Both 80 out of 100 and 40 out of 50 return 0.8.
Changing the second call's maximum to 100 produces 0.4. A function centralizes the formula, but callers must supply the correct maximum. This function assumes a positive maximum and scores between zero and that maximum.
Mutating Inputs and Reassigning Names¶
Passing a list makes the parameter refer to that list. Calling append() inside the function changes what the caller sees. Assigning a new list to the parameter name, however, does not reassign the caller's name.
Both outputs are [82, 75, 91]. The first function mutates the shared list; the second only rebinds its local name. Callers need to know whether a function changes its input or returns a new result.
Shared List Defaults¶
A mutable default such as def collect(score, results=[]): does not create an empty list on every call. Defaults are evaluated once when the function is defined, so earlier additions may remain in later calls. To create a new result for each call, default to None and create the list inside the function.
The outputs are [82] and [75]. These calls omit results, creating separate lists. Explicitly passing the same list instead keeps appending to that shared list.
Checklist¶
- Read function definitions beginning with
def. - Distinguish parameters and arguments.
- Explain
print()versusreturn. - Extract repeated calculations into functions.
- Write a function for one sample and reuse it in a loop.
- Explain assigning functions to names and passing them as arguments.
- Distinguish function and method call syntax.
- Explain how a function name should communicate intent.
-
Explain how functions turn repeated processing into named reusable units.
-
Distinguish input mutation from parameter reassignment and use a
Nonedefault when each call needs a new list.
Sources and References¶
- Python Software Foundation, More Control Flow Tools: Defining Functions, Python 3 documentation, checked on 2026-09-15. Used as the official basis for
def, parameters,return, and function-call examples. - Python Software Foundation, More Control Flow Tools: Default Argument Values, Python 3 documentation, checked on 2026-09-15. Used to confirm default-parameter examples and the caution about mutable defaults.
- Python Software Foundation, Function definitions, Python 3 documentation, checked on 2026-07-20. Used to confirm function-definition syntax, parameter lists, and function-object creation.
- Python Software Foundation, Data model, Python 3 documentation, checked on 2026-07-20. Used as background for the explanation that functions can be treated as objects in Python.
- Python Software Foundation, Classes: Method Objects, Python 3 documentation, checked on 2026-09-15. Used as the basis for distinguishing function-call and method-call forms at an introductory level.