LambdaLabTM
Computer Science · Class 12 · Functions
Functionsdef⏱️ 13 min read

Writing Your Own

Two lines of grammar and one rule of indentation. The grammar is def, a name, brackets and a colon; the rule is that everything belonging to the function is indented under it. What catches people out is not the writing — it is remembering that writing a function and running it are two separate events.

1The anatomy of a definition

anatomy.py
def welcome():
    print('Welcome to Class 12 Computer Science')
    print('Today we begin functions')

welcome()
Output
Welcome to Class 12 Computer Science
Today we begin functions
Reading the header
defwelcome():

def — the keyword that says “a definition follows”.

welcome — the name you are storing the code under. Same rules as a variable name.

() — where parameters go. Empty here, because this function needs nothing from the caller.

: — the colon that opens the block, exactly as it does after if and for.

def welcome():

The header. Running this line stores the function under the name and moves on — it prints nothing.

print('Welcome to Class 12 Computer Science')

The body, indented four spaces. Everything at this indentation belongs to the function; the first line back at the margin does not.

welcome()

The call. Now the two prints run, in order, and then the program carries on from here.

2A function you never call does nothing

This is the part worth seeing rather than being told. The function below is complete and correct, and the program prints nothing from it:

define_only.py
def welcome():
    print('this never runs')

print('The program ran, and nothing was printed by the function.')
Output
The program ran, and nothing was printed by the function.
Key Takeaway
def is a storing instruction, not a doing instruction. Python reads the header, keeps the body aside under that name, and skips past to the next line at the margin. The body is not run, not checked for sense, and not looked at again until something calls it.

3Define it before you call it

Since def is what puts the name into existence, a call placed above the definition is asking for a name that does not exist yet:

order_error.py
greet()

def greet():
    print('hello')
Output
Traceback (most recent call last):
  File "order_error.py", line 1, in <module>
    greet()
    ^^^^^
NameError: name 'greet' is not defined

Move the def above the call and it works. In practice this means definitions go at the top of a program and the lines that actually do things go at the bottom — which is how nearly every Python program you meet is laid out.

Tip
One function may call another that is defined below it. The rule is about the moment of the call, not the moment of the definition — and by the time anything actually runs, every def in the file has been read.
order_ok.py
# a() mentions b() before b exists — and that is fine,
# because nothing is called until the last line

def a():
    b()

def b():
    print('b ran')

a()
Output
b ran

4Naming a function

The rules are exactly the rules for a variable name: letters, digits and underscores, not starting with a digit, and not a keyword. The convention is lowercase_with_underscores, and the name should say what the function does:

naming.py
def print_bill_header():
    print('LAMBDALAB STORES')

print_bill_header()
Output
LAMBDALAB STORES
Watch Out
A space in the name is a syntax error. def print bill(): gives SyntaxError: expected '(' — Python read print as the whole name and then wanted the brackets, and found bill instead. Use an underscore.

5The body must exist, and must be indented

empty_body.py
def nothing():
print('x')
Output
  File "empty_body.py", line 2
    print('x')
    ^
IndentationError: expected an indented block after function definition on line 1

Python is telling you it opened a block and found nothing in it. If you genuinely want a function that does nothing yet — a placeholder you will fill in later — the body is pass:

placeholder.py
def compute_gst():
    pass          # to be written tomorrow

compute_gst()
print('the program still runs')
Output
the program still runs

6Several functions in one program

two_functions.py
def stars():
    print('*' * 20)

def title():
    print('MARKS REPORT')

stars()
title()
stars()
Output
********************
MARKS REPORT
********************

Two definitions, three calls, and the output follows the calls rather than the definitions. This is modularity in its smallest form: two named jobs, and a main program that reads as a list of them.

two_functions.py

7Recap

def name(): then an indented body

The colon opens the block and the indentation says what belongs to it, exactly as with if and for.

Defining is not running

def stores the body under the name and moves on. A function that is never called never runs.

Define above the call

The name does not exist until the def has run, so calling first raises NameError. Definitions at the top, actions at the bottom.

An empty body is an error

IndentationError: expected an indented block. Use pass for a placeholder you intend to fill in.

✍️ Now write these yourself
  1. 1

    Write print_menu(), which prints three dishes, and call it once.

    Hint · Three print() lines, all indented under the header.

  2. 2

    Write two functions, header() and footer(), and use them around a line of your own text.

    Hint · Both definitions first, then the three calls in the order you want the output.

  3. 3

    Deliberately call a function one line above its def and read the error.

    Hint · NameError. Worth doing once so you recognise it when it happens by accident.

  4. 4

    Write a function whose body is only pass, call it, and check that the program still runs.

    Hint · Nothing is printed and nothing breaks — which is what a placeholder is for.

Quick Check

What is printed by a program that defines a function and never calls it?

Quick Check

Why does calling greet() on the line above its def raise NameError?

Quick Check

What does Python say about `def nothing():` with no indented body?