8.1. Functions in Python#

8.1.1. Functions to save typing#

In programming, you often want to repeat the same sequence of commands over and over again. One way to do this is to copy and paste the same piece of code over and over again. This is actually quite easy, but quickly runs into a problem:

  • If you want to slightly change what the code does, you need to make changes in many places.

    • If you change something in one place but forget in another, then your program might give an error.

    • Or even worse, and even harder to debug, the mistake may give you the wrong answer withour giving an error.

For this reason (among others), programming languages allow programmers to define functions. Functions are pieces of code that you can give a name to, and then use time and again, without having to retype or copy-paste the code text.

As an example, let’s say we want to print out the value of variables named a and b using a long sentence:

a = 6
b = 4
print("The value of variable a is", a)
print("The value of variable b is", b)

a = a/2
b = 3
print("The value of variable a is", a)
print("The value of variable b is", b)

a = a+1
b = 1.5
print("The value of variable a is", a)
print("The value of variable b is", b)

a = a-20
b = -1e4
print("The value of variable a is", a)
print("The value of variable b is", b)

a = a+1j
b = 1
print("The value of variable a is", a)
print("The value of variable b is", b)

To save yourself a lot of typing, you can define a simple function to do this work for you. To define a function, you use the following syntax:

def function_name():
     ...

Here, you replace the ... with the code you want the function to execute. The Python code inside the function should be indented (like we’ve also seen for conditional statements and loops) by starting each line with Tab or four spaces (where consistency is really important). Python typically recognizes where indentation should occur and places the cursor for you. Note that Python also tries to detect any inconsistencies in your indentation (e.g., a mixed usage of tabs and spaces). If you make a mistake in such a way that Python cannot understand what you mean, it will give you an IndentationError.

Indentation in Python is very important: Python uses indentation to know which code is inside the function and which is not (just like we’ve seen in flow control).

Once you have defined your function, you can execute it by using function_name(). Let’s look at how to use a function as a “procedure” to simplify the code above:

def print_status():
    print("The value of variable a is", a)
    print("The value of variable b is", b)

a = 6
b = 4
print_status()

a = a/2
b = 3
print_status()

a = a+1
b = 1.5
print_status()

a = a-20
b = -1e4
print_status()

a = a+1j
b = 1
print_status()

In this example, it may not be such a big deal, but you can imagine that as the code in your function becomes more and more complicated, it will save you a lot of time. Also, imagine that we wanted to change the wording of the sentence we print: in the case with the function, we would only have to do this once, while in the example without function, we would have to manually change this at five different places.

var = 3.5

# Your code below

8.1.2. Functions with input variables#

In the example above, our function explicitly printed out variables a and b. But this only works because we know in advance that the person using our function has defined variables a and b. But what if we wanted to print the value of variable c?

Let’s say that we wanted to print out the status of variables whose name we don’t know in advance. If we wanted to make a function that could print out a message with the status of value of any variable, how could we do this? To allow functions to be more generic, and therefore more reusable in general, Python allows you to define input variables for your function. The syntax for this is the following:

def function_name(x):
    ...

When you do this, for the code INSIDE your function, a variable x is defined. x will then acquire the value that is given to the function by the user. Let’s look at an example:

def print_status_2(x):
    print("The value passed to the function is", x)

a = 1.5
print_status_2(a)

a = 1+1j
print_status_2(a)

print_status_2(1.5323)

How does this work?

When the function print_status(a) is called, Python passes (sends) the value of a to the function. Inside the function, Python creates a new (temporary) variable called x, that is defined ONLY while the function code is running. This temporary variable x is then assigned the value that was passed to the function (in this case, the value of a), and then the code is executed. When the function is finished, the variable x is destroyed. (Try adding the code print(x) above outside the function and see what happens!)

Note that the things you pass to functions don’t even need to be variables (see third example above). This is fine because the function only needs the value of the argument that is passed to the function.

# Your code here

8.1.3. Functions with multiple inputs#

Functions can also take multiple input variables. To do this, you put them all in between the brackets (), separated by commas. For example, with three variables, the syntax is:

def function_name(variable1, variable2, variable3):
    ...

After defining it, you would then use this function in the following way:

function_name(argument1, argument2, argument3)

When you do this, inside the function variable1 will get assigned the value of argument1, variable2 will get assigned the value of argument2, and variable3 will get assigned the value of argument3. This matching of the position in the list is called matching by “positional order”.

Note that there are several different names used for the “input variables” of a function: often, computer scientists use the name “input arguments” (or just “arguments), or “input parameters” (or just “parameters”).

def print_status3(x, y):
    print("The value of the first input variable is ", x)
    print("The value of the second input variable is ", y)

print_status3(1, 2)
print_status3(2.5, 1.5)
print_status3(a, 2*a)

Exercise 8.3

Make a new function print_status_4() that takes three variables as arguments and prints out messages telling the user the values of each of them (as above, but with three input variables). Test it to make sure it works.

# Your code here

8.1.4. Functions that return values#

So far we’ve mainly been looking at functions that used some input values and then printed something for us. In addition to receiving values as inputs, functions can also send back values to the person using the function. In computer programming, this is called the “return value”.

When you create a function, you can use the return command to specify what value should be sent back to the user. Let’s look at an example:

def my_formula(x):
    y = x**2 + 3
    return y

To “capture” the value returned by the function, you can assign it to a variable like this:

result = my_formula(3.5)
print(result)

You can also just directly “use” the result of the function if you want:

print(my_formula(4.6))

Note that as soon as Python sees the return command, it stops running the function, so any code after it will not be executed:

def my_function(x):
    print("This gets printed.")
    return x**2 + 3
    print("This does not.")
    
print(my_function(5))

If you want to send back more than one result to the user of your function, you can separate the results with commas when you use the return command. Let’s see how to do that:

def plus_minus(x, y):
    return x+y, x-y

addition, subtraction = plus_minus(5, 2)
print("Sum =", addition)
print("Subtraction =", subtraction)

Notice that the order of elements in return also matters (“positional order”).

a = 1.5
b = 2.5

# Your code here
import micropip
await micropip.install("jupyterquiz")
from jupyterquiz import display_quiz
import json

with open("questions3.json", "r") as file:
    questions=json.load(file)
    
display_quiz(questions, border_radius=0)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[14], line 1
----> 1 import micropip
      2 await micropip.install("jupyterquiz")
      3 from jupyterquiz import display_quiz

ModuleNotFoundError: No module named 'micropip'

8.1.5. Functions that return Booleans#

In the chapter on Flow control, we mentioned that functions in Python can return Boolean values (True or False). These return values can be useful for error handling, conditional logic, and making decisions in your code.

Python functions can perform checks and provide feedback based on the outcome of those checks. For example, a function may check whether a file exists, whether a certain condition is met, or whether an operation was successful. The returned Boolean value can then be used in an if statement to control the flow of the program.

Let’s look at a few examples.

Example 1: Checking conditions

In the code below, the is_even function checks whether a given number is even. It returns True for even numbers and False for odd numbers. This result is then used in an if statement to print whether the number is even or odd.

# Define function that checks if a number is even
def is_even(number):
    return number % 2 == 0

# Define a number (you can also try to run code with an odd number)
num = 4

# Apply function to our number within an if-else statement
if is_even(num):
    print(f"{num} is even.")
else:
    print(f"{num} is odd.")

Example 2: Validating user input

In this example, we created a function to check if the input provided by a user is a valid integer. Note that you may need to run this in VS Code as it contains input().

In this code, the is_valid_integer function attempts to convert the input value to an integer using try. If successful, it returns True; if it raises a ValueError, it returns False. This Boolean return value is then used to determine if the user input is valid.

Note: as this code uses input(), try it out in VS Code.

# Define function that checked if a vlue is integer
def is_valid_integer(value):
    try:
        int(value)
        return True
    except ValueError:
        return False

# Ask user for input value
user_input = input("Enter an integer: ")

# Apply function to user_input within an if-else statement
if is_valid_integer(user_input):
    print(f"You entered a valid integer: {user_input}")
else:
    print("That's not a valid integer!")

Example 3 (Optional): Checking if a file exists

A common usage scenario for functions that return Booleans is checking whether a file exists.

The file_exists function below returns True if the specified file exists and False otherwise.

Note that this code also uses a Python package called os, which is useful for interacting with the operating system. It contains functions that perform many OS-related tasks, such as file, directory, and path manipulation.

import os

# Define function that returns Booleand checking whether a file exists
def file_exists(filepath):
    return os.path.isfile(filepath)

# File whose existence we want to check
file_path = "example.txt"

# Applying function within an if-else statement
if file_exists(file_path):
    print(f"{file_path} exists.")
else:
    print(f"{file_path} does not exist.")