Functions
Package steps into reusable, testable pieces with inputs and outputs.
Why it matters
AI code is built from small functions. One builds the prompt, one calls the model, one scores the reply. When you ask an AI assistant to change your code, functions are the pieces you talk about: "make build_prompt include the brand voice". They also make code testable. The exercise checks in this academy work by calling your functions with known inputs and comparing what comes back.
What you'll be able to do
- Define a function with parameters and call it with arguments
- Hand a value back with return, and know when print is the wrong choice
- Give parameters default values and call functions with keyword arguments
- Explain why a variable created inside a function doesn't exist outside it
What it covers
- Packaging steps under a name
- return versus print
- Default values and keyword arguments
- Scope: what happens inside stays inside
- Worked example: scoring subject lines
- Defining isn't running
- Why functions matter later
Packaging steps under a name
So far your code has run once, top to bottom. Say you need the click-through rate for five campaigns. You could copy the formula five times. But every copy is a place for a typo, and changing the formula means changing it five times.
Think of a coffee machine. You don't explain how to make coffee each time. You press one button, and it runs the same steps. A function is that button: it packages the steps under a name, so you can run them whenever you need them:
def click_through_rate(clicks, impressions): return clicks / impressions print(click_through_rate(5470, 182340)) print(click_through_rate(2050, 410200))
The pieces:
defstarts a function definition, followed by the function's name.- The names in parentheses,
clicksandimpressions, are parameters: placeholders for the values the function will be given. - The colon and the indented block form the body, the steps that run each time.
returnhands a value back to whoever called the function.
Defining a function doesn't run it. It runs when you call it: the name, followed by parentheses holding the values to use. Those values are the arguments. In click_through_rate(5470, 182340), 5470 goes into clicks and 182340 into impressions, matched by position.
Python skips the body on line 1 until line 5 calls the function. Each call gets its own frame with its own spend, clicks and cpc, which disappears when the function returns.
return versus print
This is the most common beginner mix-up with functions:
printshows a value on the screen.returnhands a value back to the code that called the function. That code can then store it, compare it or pass it on.
A function with no return hands back None, Python's value for "nothing":
def total_with_print(a, b): print(a + b) def total_with_return(a, b): return a + b x = total_with_print(2, 3) y = total_with_return(2, 3) print("x is", x) print("y is", y)
total_with_print displayed 5, then handed back nothing, so x is None. Any calculation with x would now fail. The rule of thumb: a function that works something out should return it, and let the caller decide whether to print it.
return also ends the function immediately. Any lines after it in the same block never run, which is handy for early exits:
def roas(revenue, spend): if spend == 0: return 0 return revenue / spend print(roas(15840, 3120.5)) print(roas(500, 0))
def double(n): n * 2 print(double(4))
Show the answer
None
The body calculates n * 2 and throws the result away. Without return, the function hands back None.
Default values and keyword arguments
A parameter can have a default value, used when the caller doesn't provide one. You can also pass arguments by name, as keyword arguments, in any order:
def subject_line(product, discount=10, urgent=False): line = f"{discount}% off {product}" if urgent: line = line + " - today only" return line print(subject_line("hoodies")) print(subject_line("hoodies", 25)) print(subject_line("hoodies", urgent=True)) print(subject_line(discount=40, product="mugs"))
Two rules keep this unambiguous. Parameters with defaults come after the ones without, and in a call, positional arguments come before keyword arguments.
Keyword arguments make calls readable when a function takes several options. You'll see them everywhere in AI libraries. A call to an LLM in Python looks like client.messages.create(model="claude-opus-5-5", max_tokens=500, messages=history): every argument is labeled, so you can read it without looking up the definition.
def send(to, subject, preview=""):, which call works?Show the answer
send("ana@shop.com", subject="Hi")
Positional arguments must come before keyword ones, and to and subject have no defaults, so both are required. preview can be left out.
Scope: what happens inside stays inside
Variables created inside a function are local to it. They exist while the function runs and disappear when it returns:
def add_tax(price): tax = price * 0.2 return price + tax total = add_tax(50) print(total) print(tax)
total printed fine, but tax only ever existed inside add_tax, so the last line is a NameError. This is a feature. You can use names like total or rate inside a function without worrying about overwriting variables elsewhere in your program. What happens in the function stays in the function.
A function can read variables from outside it. But code is easier to follow when a function gets everything it needs through its parameters. Then it behaves the same wherever it's called from, and you can test it on its own.
Watch out: assigning to a name inside a function creates a new local variable, even if the same name exists outside. The outside variable is untouched.
Docstrings
A string on the first line of the body is the function's docstring: a short description of what it does. It costs one line. It pays for itself the first time you, a teammate or an AI assistant needs to use the function without reading its code.
def roas(revenue, spend): """Return on ad spend: revenue earned per unit of currency spent. Returns 0 if spend is 0.""" if spend == 0: return 0 return revenue / spend print(roas.__doc__)
rate = 5 def set_rate(): rate = 10 set_rate() print(rate)
Show the answer
5
Inside the function, rate = 10 makes a new local variable that disappears when the function ends. The outside rate is still 5.
Worked example: scoring subject lines
Score email subject lines from 0 to 3 with three simple rules: short (7 words or fewer), mentions a discount (contains "%"), and isn't written in all capitals.
def word_count(text): return len(text.split()) def score_subject(subject): """Score a subject line from 0 to 3 using simple rules.""" score = 0 if word_count(subject) <= 7: score += 1 if "%" in subject: score += 1 if subject != subject.upper(): score += 1 return score subjects = [ "Last chance: 30% off everything", "OUR BIGGEST SALE OF THE YEAR STARTS NOW FOR EVERYONE", "New arrivals you'll love", ] for s in subjects: print(score_subject(s), "-", s)
Each function does one job. word_count splits the text on spaces and counts the pieces; score_subject calls it as one of its rules. The loop at the bottom calls score_subject once per subject line. To change a rule, say to allow 9 words, you edit one line inside one function and every subject is scored the new way. Try adding a fourth rule that rewards a question mark.
Defining isn't running
Writing def greet(): only teaches Python the name. Nothing inside runs until you call it, with parentheses: greet(). Leave the parentheses off and you get the function itself rather than its result.
def double(n): print(n * 2) # shows it, but gives nothing back answer = double(5) print(answer)
This prints 10, then None. The print shows the number on screen, but the function returned nothing, so answer is empty. If other code needs the value, use return. A handy rule: functions that work something out should return it, and let the caller decide whether to print it.
Why functions matter later
Later in the course, a model decides which of your functions to call. Clear names and clean return values are what make that work, so build the habit right now, from today.
Practice what you just read
- 8 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 5 review cards for spaced repetition
Try a quiz question
A function prints its result but has no return. You store a call to it in a variable. What does the variable hold?