convert.py
= 6
weight_in_ounces
= weight_in_ounces * 28.3495
weight_in_grams
print(f"{weight_in_grams} g")
170.09699999999998 g
In previous sections you edited a script that encodes messages to Morse code. The script is good, but is not very easy to use or reusable. For someone to make use of the script, they will have to edit it and copy and paste your code every time they want to encode a different message.
Functions provide a way of packaging code into reusable and easy-to-use components. We saw plenty of examples of functions in the last chapter, e.g. print()
wraps up all the logic about exactly how to print things, all you need to do is pass in some arguments and it handles the rest. Likewise with math.sqrt()
, you don’t need to understand the algorithm it uses, simply what it needs you to pass it, and what it returns back to you.
You can also bundle up your own logic into functions, allowing you to avoid repeating yourself and make your code easier to read. To explain how they work, lets imagine we are writing some code to help us with baking recipes. Often you will need to convert between different units, for example from ounces to grams. Create a new script convert.py
with the below code and run it.
convert.py
= 6
weight_in_ounces
= weight_in_ounces * 28.3495
weight_in_grams
print(f"{weight_in_grams} g")
170.09699999999998 g
You can see this script has three main parts:
weight_in_ounces
The data processing section will work regardless of what data is inside the variable weight_in_ounces
and so we can grab that bit of code and make it usable in other contexts quite easily, using functions.
We can turn this into a function that can convert ounces to grams by using def
. To do this, type:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
This has created a new function called ounces_to_grams
which we can now call. In a similar fashion to other constructs in Python (like for
loops and if
statements) it has a rigid structure.
First we must use the def
keyword to start a function definition:
↓ def ounces_to_grams(weight): new_weight = weight * 28.3495 return new_weight
Then we specify the name that we want to give the function. This is the name which we will use when calling the function. Like anything in Python, choose a descriptive name that describes what it does:
↓ def ounces_to_grams(weight): new_weight = weight * 28.3495 return new_weight
Function definitions must then be followed by a pair of round brackets. This is a similar syntax to that used when calling a function and giving it arguments but here we’re just defining it. Between those brackets go the names of the parameters we want the function to accept (can be zero or more parameters). Here we are defining one:
↓ ↓ def ounces_to_grams(weight): new_weight = weight * 28.3495 return new_weight
Finally, the line is completed with a colon. And since we’ve used a colon, we must indent the body of the function as we did with loops and conditional statements.
↓ def ounces_to_grams(weight): new_weight = weight * 28.3495 return new_weight
Most functions will also want to return data back to the code that called it. You can choose what data is returned using the return
keyword followed by the data you want to return:
def ounces_to_grams(weight): new_weight = weight * 28.3495 return new_weight ↑
Note that the body of the function has been copied from our script above with the only change being that the variables have different names and we added a return
statement.
You can now call the function using:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
= 6
weight_in_ounces
= ounces_to_grams(weight_in_ounces)
weight_in_grams
print(f"{weight_in_grams} g")
170.09699999999998 g
In this case you have called the function ounces_to_grams
and passed in the argument weight_in_ounces
. In the fuction, weight_in_ounces
is copied to its internal variable, weight
. The function ounces_to_grams
then acts on weight
, creating the new varaible new_weight
. It then returns new_weight
, which is assigned to weight_in_grams
.
You can use your new ounces_to_grams
function to convert any numbers. Try typing:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
= 999
weight_in_ounces
= ounces_to_grams(weight_in_ounces)
weight_in_grams
print(f"{weight_in_grams} g")
28321.1505 g
Note that we can also pass the values to the function directly, e.g. type:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
= ounces_to_grams(12)
weight_in_grams
print(f"{weight_in_grams} g")
340.19399999999996 g
Note that you must pass in the right number of arguments to a function. ounces_to_grams
expects one arguments, so if you pass more or less you will get an error. Try this now:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
= ounces_to_grams() # We've removed the arguments to this function
weight_in_grams
print(f"{weight_in_grams} g")
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[10], line 5 2 new_weight = weight * 28.3495 3 return new_weight ----> 5 weight_in_grams = ounces_to_grams() # We've removed the arguments to this function 7 print(f"{weight_in_grams} g") TypeError: ounces_to_grams() missing 1 required positional argument: 'weight'
As you can see, Python tells you that you’ve given the function a wrong number of arguments. It expects 1 (weight
). Likewise, if you give too many arguments you get a similar error:
convert.py
def ounces_to_grams(weight):
= weight * 28.3495
new_weight return new_weight
= ounces_to_grams(12, 10) # We've passed too many arguments now
weight_in_grams
print(f"{weight_in_grams} g")
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[11], line 5 2 new_weight = weight * 28.3495 3 return new_weight ----> 5 weight_in_grams = ounces_to_grams(12, 10) # We've passed too many arguments now 7 print(f"{weight_in_grams} g") TypeError: ounces_to_grams() takes 1 positional argument but 2 were given
It is possible to define functions that take no arguments:
def pi():
return 3.14159
= pi() answer
single arguments:
def double(x):
return x * 2
= double(4) answer
or lots of arguments:
def lots_of_args(a, b, c, d, e):
return {"a": a, "b": b, "c": c, "d": d, "e": e}
= lots_of_args(1, 2, 3, 4, 5) answer