Skip to 0 minutes and 2 secondsOur simple function machines so far carry out single tasks in isolation. These functions are often called procedures or subroutines. Every time we call the function, it carries out its task. However, it currently doesn't accept any parameters, and doesn't give us any information back. Let's first look at parameters. Everyday machines give you some control over what they do. You could turn the temperature of an oven up or down. You could adjust the speed of a fan, or decrease the amount of water in your washing machine. Without these controls, we'd need a different machine for each type of job. Imagine needing to use a separate oven for each temperature you wanted to cook your food at. The same applies to programming functions.

Skip to 0 minutes and 45 secondsWhile simple functions allow you to package and reuse your code, unless they have control over elements or parameters, you still have to use different functions for each individual task or situation. Rather than reinvent the wheel, programmers regularly try to combine functions together, making them flexible by using parameters. Let's have a look at how this works in practice. So here we have a function that somebody has written called isWeekday. And the purpose of this function is to take a date that has been given as a parameter and find out whether it's a weekday-- i.e. Monday to Friday. It uses the weekday function, which is part of the datetime library, to determine the number of the day of the week.

Skip to 1 minute and 28 secondsAnd those numbers go from 0 for Monday all the way up to 6 for Sunday. So we want any value that is less than 5-- i.e. it's a 0 Monday, all the way up to a 4 for Friday. So what we're going to do is we're going to use an if statement to find out whether it is a weekday. So I'm going to say, if the day that I have got is less than 5, then I am going to use the return keyword, which is going to return some data back up to whichever bit of the program called this function.

Skip to 2 minutes and 1 secondAnd I'm going to say that if it is less than 5, I'm going to return true, because it is a weekday. And otherwise-- or else-- I'm going to return false. So this function, when I run it, will find out what the day of the week is for the date that has been given, and tell me true for a weekday and false for a weekend. So now if I ask it to print my isWeekday, then what should happen when I run my code is today as a Thursday when I'm filming, so I should get a true statement. And I got that wrong, because I forgot to say in here that it is datetime.now. There we go. Let's run that again.

Skip to 2 minutes and 47 secondsAnd we're going to run it on today's date. And I should get true, because today is a weekday. Now, because this function is also returning a true or false value-- a Boolean-- we can use it within if statements. So I could change the way this is written, and I could say that if isWeekday datetime.now, then print "It's a Weekday". OK, and then if it's not, then I could print-- so I'd say else-- if it's not a weekday, then I could print--

Skip to 3 minutes and 32 secondsoh, I put caps lock on there. "It's a Weekend". There we go. So now if I run my program, instead of saying true or false, it used the true or false value to determine what to print. And so it's saying "It's a Weekday", which it is. So then we've used a return value to determine the result of the function that we've just run. So let's have a look at another function that returns some data. Here we have a program which includes a getProfile function. This function asks the user for their first name, their last name, and also their age. But what we want to do is make this function return that data. So I'm going to add a return.

Skip to 4 minutes and 20 secondsAnd I'm going to simply just for now return the Firstname value. And then what I want to do in my main program is when I run and getProfile, I want to store the results of that data-- i.e. the return value. I want to store the results in a variable. So I'm going to create a new variable, which I'm going to call fname. My names can be different. They can be the same. It's fine. And I'm going to say that fname equals getProfile. And then just to make sure it's worked, I'm going to print fname.

Skip to 4 minutes and 54 secondsNow if I run my program, it's going to ask me what my first name is. It's going to ask me what my last name is. It's going to ask me what my age is. Let's say I'm 30, for argument's sake. Put that in, and it has printed out my fname-- my first name, which is James. So that's worked. But I can also do some really powerful things. I can say that actually, I want to return not just the first name, but last name and age as well. And all I need to do in Python is say that I've got not one variable where I'm storing the information, but I've got three variables.

Skip to 5 minutes and 33 secondsSo I'm going to say name, and I'm going to call this one age. Now, the reason I can call this one age is because this variable here-- this age-- is inside the getProfile function, and is only visible to the getProfile function. This age is a different variable that is also called age. It exists outside the function. Let's just make sure his program works. If I say fname also you print lname and also print age, when I run that program again and I tell it who I am-- James, surname-- then it's printed those three bits of information out. So there we go.

Skip to 6 minutes and 23 secondsWe've seen in these examples that we can return Boolean data, we can retain lists or strings, or anything else for that matter. And once we've returned that data, we can store that in a variable to use later as the program runs. Once you've gotten to grips with creating your own functions, you can begin to add more structure to your programs, taking each component of the program and creating a reusable function from it. Let's imagine we wanted to create a program that could convert a string message into a series of flashes on an LED to create a Morse code sequence. We might have a really high level abstract function called morseMessage.

Skip to 6 minutes and 59 secondsIts job is to take a string message and create from it a sequence of flashes of our LED. It does this using four smaller functions. The first one, called char lookup, takes an individual character and converts it into a sequence of dots, dashes, and pauses. The morseMessage function uses that information to then either flash a dot, a dash, or a pause using the smaller component functions. So hopefully now you've got a good understanding of how our functions can be adapted using parameters and return values. Can you apply what you've learned? You'll find some small challenges at the end of this step to complete and share with your fellow learners.

Functions including parameters and returns

So far, you’ve used and created simple functions that carry out one task in isolation. This type of function is often refered to as a procedure or subroutine. These functions might accept parameters, but they do not return any information to the program that called them.

In this step, you’ll learn more about these two aspects of functions - parameters and return values - and how they make functions incredibly useful.

Let’s reuse the analogy from the previous step, and imagine our function as a machine carrying out a some computational task when switched on or called. A simple function or procedure is like a basic machine: it does one fixed task, like a kettle. We turn it on, it does the task, and we recieve no real feedback from the machine. Every time this function is called it carries out its task.

An animation of a machine labelled "function". The machine is initially stationary. A button labelled "call" on the machine is activated, the label "finished" on the machine turns into "called", and some pistons on the machine start moving. After a couple of seconds, the machine stops and the "called" label turns into "finished".

Parameters = inputs

Most everyday machines allow us some control over what the machine does: the temperature of an oven, the speed of a fan, or the amount of water a washing machine should use. Without these controllable elements we’d need a different machine with a different setting for every job, e.g. a different oven for each temperature we want to cook at.

It’s a similar story with programming. Whilst simple functions allow a programmer to package up code and reuse it, without controllable elements they would need a different function for every scenario, even if they are very similar.

Rather than re-invent the wheel every time, a programmer will create a function that can apply to multiple situations and be tailored to each one, using inputs or parameters.

For example, here’s a pair of functions that each load some map data from a file. As you can see, they have very similar actions: they each open a text file in r (read) mode, and add the contents of the file to a list.

map1 = [] #Creates an empty list

#Here we define the function
def load_level_1():
    with open("map1.txt",mode="r") as file:
        for line in file:
            map1.append(line.strip().split(","))
map2 = [] #Creates an empty list

#Here we define the function
def load_level_2():
    with open("map2.txt",mode="r") as file:
        for line in file:
            map2.append(line.strip().split(","))

Such duplication in programs can be avoided by writing a single function with parameters, which can then be used to load either map data file. Here the parameters have been given descriptive names (file and map), but you can call them anything you like. The names don’t need to relate to anything in the rest of the program: they only exist within the scope of this function.

map1 = []
map2 = []

def load_level(file,map):
    with open(file,mode="r") as file:
        for line in file:
            map.append(line.strip().split(","))

This function can then be called, and will use whichever map file and variable you ask for:

load_level("map1.txt",map1)

An animation of a machine labelled "load_level". The machine is initially stationary. A button labelled "call" on the machine is activated, two boxes labelled "file" and "map" move down two pipes into the machine. The label "finished" on the machine also turns into "called", and some pistons on the machine start moving. After a couple of seconds, the machine stops and the "called" label turns into "finished".

Return values = outputs

A real life machine, like the functions we have seen, has consequences or side effects: it washes clothes, cooks food, or boils water, for example. However, unlike the functions we’ve seen so far, it may also provide some feedback or information as output. Machines might beep, display some text, or sound an alarm, for example. A function can also provide information, simply by returning some data to the program that called it.

When programming, you will often need to get data back from a function, either simply to confirm that the function has done its job, or to get some richer data that the function has calculated. This is done via the return command, which “returns” data back to the process that called the function. In the simple example below, the function isWeekday checks whether the date provided is a weekday.

from datetime import datetime

def isWeekday(mydate):
    day = mydate.weekday()  #Get the nunber of the day of the week - Monday = 0, Tuesday = 1 etc.
    if day < 5:
        return True
    else:
        return False

# Calls the function providing a date
workday = isWeekday(datetime.now())  #Call the isWeekday function with today's date, store the returned data in a variable "workday".

Once defined, a function like isWeekday, which returns a True or False (Boolean) value, can be used in conditional statements:

if isWeekday(datetime.now()):
    print("It is a week day")

Of course, functions aren’t just limited to returning Boolean values. They can return any variable, list, or other object. For example, the following function asks the user to input some numbers, and then returns the same numbers as a list.

def getNums(size):
    nums = []
    for x in range(size):
        num = int(input("Enter a whole number: "))
        nums.append(num)
    return nums


mynums = getNums(10)

An animation of a machine labelled "get_nums". The machine is initially stationary. A box labelled "size" drops onto a conveyor belt to the left of the machine. A button labelled "call" on the machine is activated, the label "finished" turns into "called", some pistons on the machine start moving and the box moves along the conveyor belt and into the left side of the machine. After a few seconds a box labelled "nums" moves out of the right hand side of the machine, on a conveyor belt. The machine stops and the "called" label turns into "finished".

You can even return several values from one function and then store these in separate variables:

def get_profile():
    firstname = input("What is your first name? ")
    lastname = input("What is your last name? ")
    age = int(input("What is your age? "))

    return firstname, lastname, age


fname,lname,user_age = get_profile()

In this example, we have used different variable names when calling the function from the variable names inside the function. Whilst this is good practice as it helps the programmer distinguish between them, it is not actually necessary in Python. In other words, we could have called the function like this:

firstname,lastname,age = get_profile()

Variables defined inside a function, like firstname, exist in isolation from other variables and only whilst the function is run. This is their scope. Variables defined in the main program, rather than within functions, exist for the duration of the program and are said to be global in scope. If you want a function to have access to variables outside its own scope, best practice would be to add them as parameters to the function:

am = "Good Morning"
pm = "Good Evening"

def get_profile(msg):

    print (msg)
    firstname = input("What is your first name? ")
    lastname = input("What is your last name? ")
    age = int(input("What is your age? "))

    return firstname, lastname, age

#Function called passing in variable from global scope
fname,lname,user_age = get_profile(am)

Combining functions

Once you’ve got to grips with creating your own functions, you can begin to add more structure to your programs, taking each component of the program and creating a reusable function from it.

For example, imagine you wanted to create a program that could send Morse code messages by blinking a single LED. This problem can be broken down into a hierarchy of functions.

  • The highest or most abstract function might be morseMessage(), whose job is to take a given string and turn it into a Morse sequence. To do this, it will call charLookup() for each character in turn, and then the relevant dot, dash, and pause functions.
  • The charLookup() function looks up a given character and determines the correct sequence of dots, dashes and pauses for that character. This sequence is returned as a string to the morseMessage() function.
  • The dot(),dash(), and pause() functions receive no input, and simply turn the LED on and off for the appropriate lengths of time to represent dots and dashes.

We could represent this diagramatically like this:

An arrow labelled "Message (string") point at a block labelled "morseMessag(string)". An arrow labelled "Character(string)" goes to a block labelled "charLookup(string)", and another arrow labelled "Morse code (string)" goes from  "charLookup(string)" to "morseMessage(string)". Three other unlabeled arrows go from "morseMessage(string)" to one of three separate blocks, which are labeled as "dash()", "dot()" and "pause()".

An example of the full code for a Morse code generator can be found here.

Over to you

Can you create your own functions that use parameters and return values? Pick one of these challenges to complete, and share your code in the comments for this step.

  • Create a function that accepts the dimensions of a triangle and returns its area.
  • Create a function that accepts a string and returns the same string reversed.
  • Create a function that simulates a pair of dice being rolled n times and returns the number of occurrences of each score.

Share this video:

This video is from the free online course:

Programming 102: Think Like a Computer Scientist

Raspberry Pi Foundation