Functions¶
Mathematical functions are rules for turning given inputs into specific outputs. For example,
maps the input 4 to the output 16 and the input 9 to the output 81. Python functions are similar: they take in inputs, do specified computation, and give back outputs. Programming tasks that need to be done repeatedly, but with different inputs, are best formulated as functions.
Avoid Copy + Paste
Functions make it possible to reuse the same piece of code many times. If you find yourself copying and pasting the same chunk of code repeatedly, consider writing a function instead. This will save you time and make it easy to globally update the behavior of the reused chunk of code if needed.
Defining Functions¶
Python functions are defined with a block of code that has three main parts:
the signature,
an optional docstring, and
the body.
The following code defines a function named circle_area() for computing the area of a circle,
given a radius \(r\) (using the first six digits of \(\pi\)).
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
Signature¶
The function signature defines the name of the function and its inputs.
The keyword
defbegins the definition of the function.The word following
defis the name of the function. Function names must follow the same rules as variable names: start with a letter and use only letters, numbers, and underscores.Immediately after the function name, parentheses
(and)enclose the function parameters, the inputs. Functions can have one or many inputs, or none at all. Parameters are temporary variables within the function body.The colon
:marks the end of the function signature.
The circle_area() function has a single parameter, radius.
Lines after the signature that are indented with four spaces form the rest of the function definition. Code that is unindented is no longer part of the function definition.
Docstring¶
If the first line after the signature is a triple-quoted string, it is called the docstring. The docstring gives human-readable instructions and context about the function, its inputs, and its outputs. Like comments, docstrings do not affect the actual execution of the function.
Because circle_area() is quite simple, a single-line description suffices as the docstring.
Write Quality Docstrings
Clear, readable docstrings are extremely important if you want anyone (including your future self) to be able to read or use your code. When you define a function, always write at least a short docstring describing what the function does.
Body¶
The function body is everything after the docstring until the indentation goes back to the same level as def.
The body of the function can be several lines long and is where the action happens.
Within the body, the function parameters are available as temporary variables.
The body usually ends with a return statement which indicates the function output or outputs.
If a function does not have a return statement, Python treats it as if the body ended in the line return None.
The constant None is a placeholder indicating “no value.”
The body of circle_area() consists of a single line, the return statement.
In this case, the area \(\pi r^2\) is computed as a float, and this float is the function output.
More Examples¶
def cone_volume(baseradius, height):
"""Compute the volume of the cone of the given radius and height.
Parameters
----------
baseradius : float
Radius of the circular base of the cone.
height : float
Height of the cone, the distance from the circular base to the point.
Returns
-------
volume : float
Volume of the specified cone.
"""
return 3.14159 * baseradius**2 * height / 3
This block defines a function named cone_volume() with two parameters: baseradius and height.
def cone_volume(baseradius, height):
"""Compute the volume of the cone of the given radius and height.
Parameters
----------
baseradius : float
Radius of the circular base of the cone.
height : float
Height of the cone, the distance from the circular base to the point.
Returns
-------
volume : float
Volume of the specified cone.
"""
return 3.14159 * baseradius**2 * height / 3
The docstring is several lines long and includes sections describing the inputs and outputs and their expected data types (float).
def cone_volume(baseradius, height):
"""Compute the volume of the cone of the given radius and height.
Parameters
----------
baseradius : float
Radius of the circular base of the cone.
height : float
Height of the cone, the distance from the circular base to the point.
Returns
-------
volume : float
Volume of the specified cone.
"""
return 3.14159 * baseradius**2 * height / 3
The body is a single line consisting of the return statement.
def exclaim():
"""Print a very long word forward and backward."""
print("supercalifragilisticexpialidocious!")
print("suoicodilaipxecitsiligarfilacrepus?")
This block defines a function named exclaim(), which does not have any parameters.
def exclaim():
"""Print a very long word forward and backward."""
print("supercalifragilisticexpialidocious!")
print("suoicodilaipxecitsiligarfilacrepus?")
The docstring is a brief one-line description.
def exclaim():
"""Print a very long word forward and backward."""
print("supercalifragilisticexpialidocious!")
print("suoicodilaipxecitsiligarfilacrepus?")
The body is two lines long and does not contain a return statement, so the function always returns None.
Calling Functions¶
After a function has been defined, it can be used by writing the function name followed by parentheses ( and ) around a comma-separated list of arguments to match the function parameters.
This is referred to as calling the function.
The arguments are temporarily assigned to the parameters each time the function is used.
The values in the return statement are then returned and can be stored as variables.
# Call circle_area(). The parameter `radius` is assigned to the argument value 1.
area1 = circle_area(1)
print(area1)
# Call circle_area(). The parameter `radius` is assigned to the argument value 10.
area10 = circle_area(10)
print(area10)
3.14159
314.159
If a function has no parameters, it is called with (), without any arguments.
# Call exclaim() twice.
a = exclaim()
b = exclaim()
# The return value of exclaim() is None.
print(a)
supercalifragilisticexpialidocious!
suoicodilaipxecitsiligarfilacrepus?
supercalifragilisticexpialidocious!
suoicodilaipxecitsiligarfilacrepus?
None
Problem 2
For \(0 < x \le 2\), the natural logarithm \(\ln(x)\) can be written as the infinite series
This is called the Taylor series for \(\ln(x)\) centered around \(x = 1\). Although a computer cannot add up infinitely many numbers (it would take infinitely many computations), the sum can be approximated by adding together the first several terms.
Write a function named natural_log() that accepts a float representing \(x\) and returns an estimate for \(\ln(x)\) using the first 5 terms of the above series.
That is, natural_log(x) should return the number
which will be close to the true value of \(\ln(x)\) if \(x\) is near \(1\). Include a brief docstring describing the function.
Spelling Matters
The functions in this and the following problems must be named exactly as described, otherwise the autograder will not be able to find and test them.
Test Cases
To test your function, call it with a few different input values using the following code and compare the results to those listed below.
print(natural_log(0.8))
print(natural_log(1.0))
print(natural_log(1.2))
-0.22313066666666664
0.0
0.18233066666666664
Spot Checks Don’t Guarantee Correctness
This test is only a spot check! Matching given outputs does not guarantee that the function always returns the right result for every possible input. However, if the outputs do not match (or if calling the function raises an error), this indicates that something is wrong with the function definition or the arguments being used.
Scope¶
Parameters are temporary variables that are only available within the body of a function definition.
def identity(my_parameter):
return my_parameter
# Don't treat a parameter like a variable outside of the function definition.
identity(5)
print(my_parameter)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 7
3
4
5 # Don't treat a parameter like a variable outside of the function definition.
6 identity(5)
----> 7 print(my_parameter)
NameError: name 'my_parameter' is not defined
Likewise, any variables defined within a function are not available outside of the function definition.
def find_meaning():
purpose = 42
# Variables defined in a function body are not available elsewhere.
find_meaning()
print(purpose)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 7
3
4
5 # Variables defined in a function body are not available elsewhere.
6 find_meaning()
----> 7 print(purpose)
NameError: name 'purpose' is not defined
On the other hand, variables that are defined outside of all function definitions are called global variables and can be used within a function definition.
phi = 1.61803398875
def how_close_to_golden(a, b):
"""Compute how close a/b is to the golden ratio."""
return (a / b) - phi # phi can be used here.
print(how_close_to_golden(144, 89))
-5.646066011233408e-05
Quick Check
The following code has an error in it. What is the problem?
def portion(a, b):
total = a + b
return a / total
c = portion(3, 5)
print(c)
print(total)
Answer
The variable total is defined in the function body of portion(), so it is a local variable that is not available outside of the function definition.
This results in a NameError on the final line because the program cannot find a variable named total.
Functions can call other functions in the body of their definition.
Consider again cone_volume(), a function for computing the formula
Since circle_area() is a function used to compute \(\pi r^2\), the definition of cone_volume() can be modified to use circle_area() for that computation (the docstring is omitted below for brevity).
def cone_volume(baseradius, height):
return 3.14159 * baseradius**2 * height / 3
This is the definition from earlier.
def cone_volume(baseradius, height):
return circle_area(baseradius) * height / 3
This calls circle_area() with baseradius as the argument corresponding to the parameter radius.
With the call, if circle_area() is altered to use a better approximation for \(\pi\), the new approximation is automatically used in cone_volume().
Evaluation Order¶
Consider a function for calculating the area of a disc (a circle with a hole in it) that uses circle_area() twice in its definition.
Click through the tabs to see how the program reads and executes the code.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
Python reads the function definitions.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The next line is executed, starting with the call disc_area(3, 5).
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The call disc_area(3, 5) causes the program to jump back to the function definition for disc_area() and assign inner_radius = 3 and outer_radius = 5 for the duration of the function body.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The first line of the function body is executed, starting with the call circle_area(inner_radius).
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The call circle_area(inner_radius) causes the program to jump back to the function definition for circle_area() and assign radius = inner_radius for the duration of the function body.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The first line of the function body is executed, returning the value of 3.14159 * radius**2.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The program returns to the line it was executing when circle_area(inner_radius) was called.
The value returned by the call is stored as a variable.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The next line of the function body is executed, starting with the call circle_area(outer_radius).
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The call circle_area(outer_radius) causes the program to jump back to the function definition for circle_area() and assign radius = outer_radius for the duration of the function body.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The first line of the function body is executed, returning the value of 3.14159 * radius**2.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The program returns to the line it was executing when circle_area(outer_radius) was called.
The value returned by the call is stored as a variable.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The next line of the function body is executed, returning the value of larger_circle_area - smaller_circle_area.
def circle_area(radius):
"""Compute the area of the circle with the given radius: A = π r^2."""
return 3.14159 * radius**2
def disc_area(inner_radius, outer_radius):
"""Compute the area of a disc, the region between two circles with the same
center but different radii.
Parameters
----------
inner_radius : float
Inner disc radius, the distance from the center to the start of the disc.
outer_radius : float
Outer disc radius, the distance from the center to the end of the disc.
Returns
-------
area : float
Area of the specified disc.
"""
smaller_circle_area = circle_area(inner_radius)
larger_circle_area = circle_area(outer_radius)
return larger_circle_area - smaller_circle_area
print(disc_area(3, 5))
The program returns to the line it was executing when disc_area(3, 5) was called.
The value returned by the call is used as an argument for print(), which displays the result.
50.26544
In nested function calls like f(g(h(x))), the functions are evaluated from the inside out: first h, then g, then f.
# Written in one line.
result = f(g(h(x)))
# Written one step at a time.
y = h(x)
z = g(y)
result = f(z)
Problem 3
Euler’s constant \(e\) is the base of the exponential function \(e^x\). One way to define \(e\) is as the limit
To estimate this limit, we can compute \((1 + \frac{1}{n})^n\) for a large (but finite) number \(n\). The following function implements this idea.
def exponential_constant(n):
"""Estimate Euler's constant e as (1 + 1/n)^n for the given n."""
return (1 + (1 / n)) ** n
Like the function natural_log() from Problem 2, the function exponential_constant() only computes an approximation.
To check how good the approximation is, we can use the fact that the exponential and natural logarithm are inverses: \(e^{\ln(x)} = x\), so then \(x - e^{\ln(x)} = 0\).
Write a function named explog_error() that accepts two arguments (in this order):
A
floatrepresenting \(x\), andAn
intorfloatrepresenting \(n\).
Compute and return the difference
\(
x - e^{\ln(x)}
\)
where \(e\) is estimated with exponential_constant() and \(\ln(x)\) is estimated with natural_log().
Test Cases
print(explog_error(1.314, 2))
print(explog_error(1.314, 10))
print(explog_error(1.314, 50))
0.06599324187790923
0.016565007091014605
0.003372826007180585
Multiple Return Values¶
Functions can return more than one value by using commas in a return statement.
The return values can be extracted individually by using commas to the left of the = operator.
def powers(x):
"""Raise `x` to the second, third, and fourth power."""
return x**2, x**3, x**4
# Call the function and store all return values at once.
a2, a3, a4 = powers(3)
print(a2)
print(a3)
print(a4)
9
27
81
Many Unused Returns
A function can have multiple return statements, but this does not mean that it returns multiple values.
Consider the following incorrect implementation of the powers() function from above.
1def powers_bad(x):
2 """Raise `x` to the second, third, and fourth power, purportedly."""
3 return x**2
4 return x**3
5 return x**4
When the return statement on line 3 is executed, the function exits and execution immediately resumes at the line of code that called the function.
The other return statements in lines 4 and 5 are never reached.
Hence, this function only returns one value: x**2.
Built-in Functions¶
Python provides several basic functions that are always available.
We have already seen print(), which prints a string representation of the arguments to the screen.
Here are a few other useful built-in functions.
Signature |
Returns |
Description |
|---|---|---|
|
Print a string representation of each argument. |
|
|
Return the absolute value of |
|
|
Round a number |
|
|
Round a number |
|
|
Do integer division of \(a \div b\) with a remainder |
Note that print() does not return anything, abs() and round() return a single number, and divmod() returns two numbers.
x = 3 * (2**6) - 2 * (3**5)
print(x)
# Compute the absolute value of x.
print(abs(x))
-294
294
# Round a number to the nearest integer.
pi = 3.14159265358979323486264338
print(round(pi))
# Round the same number to four and eight decimal places.
print(round(pi, 4))
print(round(pi, 8))
3
3.1416
3.14159265
# Print several values on the same line.
print(pi, abs(pi), round(pi))
3.141592653589793 3.141592653589793 3
Problem 4
Recall the creamery from Problem 1 that has the following menu items.
Box of French fries, $2.49
Guacamole bacon burger, $8.69
Single scoop of ice cream, $3.99
Write a function named creamery_bill() that accepts three int arguments (in this order):
The number of boxes of French fries to order.
The number of guacamole bacon burgers to order.
The number of single scoop ice creams to order.
Calculate the total cost of the order with the given numbers of items, including the 7.45% tax and the $5.00 coupon. Return the result, rounded to the nearest cent (two decimal places).
Test Cases
print(creamery_bill(2, 2, 2)) # 2 of each
print(creamery_bill(1, 2, 3)) # 1 fries, 2 burgers, 3 ice creams
print(creamery_bill(0, 3, 5)) # 3 burgers, 5 ice creams
27.6
29.21
44.45
Additionally, creamery_bill(3, 2, 2) should nearly equal problem1_total (with perhaps a small difference due to rounding).
The built-in function divmod() performs integer division and returns both the quotient and the remainder.
# 131 divided by 7 is 18 with remainder 5
quotient, remainder = divmod(131, 7)
print(quotient)
print(remainder)
18
5
The following is a simplified definition for divmod().
def divmod(a, b):
"""Return the integer quotient and remainder for `a` divided by `b`."""
return a // b, a % b
Problem 5
One inch equals 2.54 centimeters. Therefore,
There are 12 inches in a foot.
Write a function named cm2ftin() that accepts a single argument representing a length in centimeters.
Convert the length to inches, round the total number of inches to the nearest whole inch, then return two values: the number of feet and the remaining inches.
Test Cases
# 2.54 centimeters = 0 feet, 1 inch
feet, inches = cm2ftin(2.54)
print(feet)
print(inches)
0
1
# 1000 centimeters = 10 meters = 32 feet, 9.7 inches
feet, inches = cm2ftin(1000)
print(feet)
print(inches)
32
10