Functions
See csse1001 for course logistics — this note covers Lecture 3A’s technical content.
Today’s outline
- What a function is and how to define one
- The
returnstatement, and how it differs fromprint - Improving functions with type hints and docstrings
Learning objectives
- User-defined functions bundle code together and are the building blocks of more sophisticated programs.
returnhands back a value and exits a function; it is not the same asprint.- Functions can be documented with type hints and docstrings.
What is a function?
We have already used functions — * and max, for example — each of which takes input and returns output. User-defined functions let us name and reuse our own bundles of code, just like a mathematical function such as \(f(x) = x^2+x+1\):
>>> def f(x):
... return x**2 + x + 1
>>> f(3)
13
See python-functions for the full syntax rules (indentation, multiple parameters, the return statement, return vs. print, type hints, and docstrings) — used throughout the rest of this note.
Building up Heron’s formula
Exercise. The area of a triangle with side lengths \(a, b, c\) is \(\sqrt{s(s-a)(s-b)(s-c)}\) where \(s = \tfrac{1}{2}(a+b+c)\) (Heron’s formula). What is the area of the triangle with sides 3, 4, and 5?
As a calculator, we’d have to type this out in full, and it would be tedious to repeat for other side lengths:
>>> (0.5*(3+4+5)
... *(0.5*(3+4+5)-3)
... *(0.5*(3+4+5)-4)
... *(0.5*(3+4+5)-5))**0.5
6.0
Using names and sequencing (see 2025-08-04-python-memory-model) avoids repeating the same sub-expression:
>>> a, b, c = 3, 4, 5
>>> s = (a + b + c)/2
>>> (s*(s-a)*(s-b)*(s-c))**0.5
6.0
Wrapping it in a function makes it reusable for any triangle:
>>> def heron(a, b, c):
... s = (a + b + c)/2
... return (s*(s-a)*(s-b)*(s-c))**0.5
>>> heron(3, 4, 5)
6.0
Improving the function
Adding type hints and a docstring (see python-functions):
>>> def triangle_area(a: float, b: float, c: float) -> float:
... """
... Return the area of the triangle with sides length <a>,
... <b>, and <c>.
... Preconditions: <a>, <b>, <c> are all nonzero positive.
... >>> triangle_area(3, 4, 5)
... 6.0
... """
... s = (a+b+c)/2
... return (s*(s-a)*(s-b)*(s-c))**0.5
>>> triangle_area(2.2, 3.3, 4.4)
3.5147323866832307
See python-pep8-style-guide for the naming, spacing, and line-length conventions expected of functions like this.
return vs. print: quick check
>>> def example(x):
... print(1*x)
... return 3*x
... print(2*x) # never runs -- return already exited the function
>>> a = example(1)
1
>>> a
3
>>> def foo(x):
... if x > 0:
... print("Positive")
... if x > 10**5:
... print("Large positive")
>>> ans = foo(10**6)
Positive
Large positive
>>> type(ans)
<class 'NoneType'>
foo above never hits a return, so it defaults to returning None even though it printed something. Contrast with a version that returns instead:
>>> def bar(x):
... if x > 0:
... return "Positive"
... if x > 10**5:
... return "Large positive"
>>> ans = bar(10**6)
>>> ans
'Positive'
bar exits at the very first return it reaches, so "Large positive" is never returned even though x > 10**5 is also true.
Exercise: the middle number
Write a function that takes three integers and returns the number that is not the largest or the smallest:
def middle_number(x: int, y: int, z: int) -> int:
"""
Return the number that is not the largest or smallest
among the three inputs.
Precondition: the numbers are distinct.
>>> middle_number(3, 1, 2)
2
>>> middle_number(2, 3, 1)
2
"""
return (x + y + z) - min(x, y, z) - max(x, y, z)
Summary
Blocks of code can be grouped into functions. Functions take zero or more inputs and hand back a single value designated by return.
Next lecture
2025-08-11-sequence-selection-and-iteration — selection.