LambdaLabTM
Computer Science · Class 12 · Functions
FunctionsThe idea⏱️ 12 min read

What a Function Is

A function is a piece of code with a name attached to it. You write the code once, under that name. Then, wherever you need it, you write the name — and the code stored under it runs. That is the whole idea, and everything else in this chapter is detail.

📘 Definition

A function is a named block of code that performs a specific, well-defined task. It is written once and can be reused any number of times by referring to its name.

The name is the identifier associated with that block. When the name is used — with brackets after it — the block of code stored under that name is executed. Functions are what make a program modular: a long program is divided into smaller, manageable, logical units, each doing one job.

1The problem functions solve

Here is a bill. The line of dashes is printed four times, and each time it is typed out again in full:

repeated.py
# the same line, typed out four times

print('-' * 40)
print('BILL')
print('-' * 40)
print('Pens      3 x 10 = 30')
print('-' * 40)
print('TOTAL 30')
print('-' * 40)
Output
----------------------------------------
BILL
----------------------------------------
Pens      3 x 10 = 30
----------------------------------------
TOTAL 30
----------------------------------------

It works. But if the shop decides the bill should be 50 characters wide instead of 40, you have four lines to find and change — and this is a four-line bill. On a real one you would have twenty, and you would miss one.

2Give the code a name

with_function.py
# the line is written once, under the name 'line'

def line():
    print('-' * 40)

line()
print('BILL')
line()
print('Pens      3 x 10 = 30')
line()
print('TOTAL 30')
line()
Output
----------------------------------------
BILL
----------------------------------------
Pens      3 x 10 = 30
----------------------------------------
TOTAL 30
----------------------------------------

Identical output. The difference is that the instruction print('-' * 40) now exists in one place. Change the 40 to a 50 there, and every line in the bill changes with it.

Look closely at the two lines that make the function. They are not the same kind of line, and each has a name:

Header and body
def line():← the header — gives the block its name
print('-' * 40)← the body — the actual code, indented

The header is the def line. It supplies the name (identifier) the block will be stored under, and it ends in a colon. The colon is a promise that an indented block follows.

The body is everything indented under that header. This is the actual code — the work the function does. Indentation is what marks it out: the first line back at the left margin is no longer part of the function.

So the header names a block, and the body is the block. That is the whole shape of a function, and it is the same shape you already know from if and for — a line ending in a colon, then an indented block belonging to it. A function body can hold as many lines as the job needs, and every one of them must be indented by the same amount.

longer_body.py
# four lines in the body, all indented under the header

def banner():
    print('-' * 30)
    print('LAMBDALAB')
    print('-' * 30)
    print('Welcome')

banner()
print('back at the margin, outside the function')
Output
------------------------------
LAMBDALAB
------------------------------
Welcome
back at the margin, outside the function

The last print starts at the left margin, so it is not in the body — it belongs to the main program and runs after the function has finished.

The two halves of a function
1 · Defining it
def line(): print('-' * 40)

Storing the code under a name. Nothing is printed. Nothing runs.

2 · Calling it
line()

Writing the name, with brackets. Now the stored code runs.

3The name is doing the work

Read the call again: line(). Python looks up the name line, finds the code you stored under it, and runs that code. Then it comes back and carries on with the next line of your program. Every call does the same thing.

greet.py
# one definition, three calls

def greet():
    print('Good morning, class!')

greet()
greet()
greet()
Output
Good morning, class!
Good morning, class!
Good morning, class!
Watch Out
The brackets are what make it a call. The name on its own — greet without () — is just a mention of the function, the way marks is a mention of a list. Python looks it up, finds a function, and does nothing with it:
name_only.py
def greet():
    print('Good morning, class!')

print('before')
greet          # a mention, not a call — nothing happens
print('after')
Output
before
after

4Invocation: the call is what activates it

Writing a function and running it are two separate events, and the second one has a name. Using a function — writing its name with brackets — is called invoking it, or calling it. The two words mean exactly the same thing, and both turn up in exam questions.

📘 Definition — function call / invocation

A function call (or function invocation) is the statement that activates a function — it transfers control to the block of code stored under that name and executes it.

A function definition merely stores the code under a name. It does not activate it. Until the function is invoked, not one line of its body is ever executed.

The proof is a program that defines a function perfectly well and never invokes it:

never_invoked.py
def line():
    print('-' * 40)          # this line is never executed

print('program started')
print('program finished')
Output
program started
program finished

Not a single dash. The definition ran — the name line now exists and the code is stored under it — but without an invocation the body simply sits there.

Definition — stores
def line(): print('-' * 40)

Written once. Creates the name. Runs nothing. Happens whether you ever use the function or not.

Invocation — activates
line()

Written as often as you like. Transfers control into the body, runs it, and comes back. This is the event that produces output.

Key Takeaway
One definition, any number of invocations. That asymmetry is the whole value of a function: the code is written once and activated as many times as the program needs — three times in the greeting example above, four times in the bill, and never at all in the program you just read.

5Modularity: one big program, many small pieces

The bill example saves you some typing. The real reason functions matter is bigger than that, and it has a name: modularity.

Key Takeaway
Modularity means splitting one long program into smaller logical units that each do one job. Each unit is a function with a name that says what it does. The program then reads as a list of jobs rather than as three hundred lines of detail, and each job can be written, tested and fixed on its own.

Compare the two ways of describing the same billing program:

Without functions

300 lines, top to bottom. To find the bit that works out GST you read until you recognise it. To fix a rounding bug you hope it only happens in one place. Two people cannot work on it at once.

With functions
print_header() items = read_items() total = compute_total(items) gst = compute_gst(total) print_footer(total, gst)

Five lines that say what the program does. The GST bug is in compute_gst, and nowhere else.

That right-hand version is the point of this chapter. Each of those names is a function; each holds a handful of lines; and the main program becomes short enough to read in one go.

6What you get from a function

Reusability

Write it once, call it as often as you like — three times or three hundred, from anywhere in the program.

Modularity

One long program becomes a set of small units, each doing one job, each with a name that says what it is.

One place to fix

A bug in the code lives in exactly one function. Correct it there and every call is corrected.

Readability

compute_gst(total) says what is happening. The eleven lines that do it are somewhere else, and you can read them when you care.

line.py

7Recap

A function is code with a name on it

def stores the code under the name. Nothing runs at that moment.

The call is what activates it

Calling — or invoking — transfers control into the body. A function that is defined but never invoked runs nothing at all.

The brackets make it a call

greet is a mention and does nothing. greet() is a call and runs the function.

Modularity is the real prize

The program becomes a set of small named units instead of one long list of instructions.

✍️ Now write these yourself
  1. 1

    Write a function stars() that prints a row of 20 asterisks, and call it three times.

    Hint · def stars(): with print('*' * 20) indented under it.

  2. 2

    Write a function that prints your school's name and address, and use it at the top of two different bills.

    Hint · Several print() lines in one function. Change the address once and both bills change.

  3. 3

    Take a program you wrote in Class 11 and name three jobs inside it that could each become a function.

    Hint · Look for anything you could describe in three words — “read the marks”, “work out the average”, “print the report”.

Quick Check

What does def line(): actually do when the program reaches it?

Quick Check

What does the program print if you write greet without the brackets?

Quick Check

A program defines a function and never calls it. What runs?

Quick Check

What does modularity mean?