Python Intermediate Series – Subroutines

Introduction

Python Intermediate Series – Subroutines; picks up where my Python Beginners Series left off. I assume that you are familiar with your IDE and that you are comfortable using:

  • print
  • input
  • variables
  • basic data types (string, int, float)
  • lists
  • loops (for and while)
  • Boolean logic (and, or not)

If you are uncomfortable with the above, parts of the intermediate series will not make sense. Please review the topic in the beginner’s series before continuing. For those that prefer a video to written tutorials it’s available at the bottom of this pose or by clicking here.

What is a Subroutine? – Python Intermediate Series – Subroutines

A subroutine is a set of instructions within the programmer’s instruction. For example, in the diagram below, the subroutine’s name is ‘DoSomething’, with two instructions; the first is to take an input and store it in a variable, then print out a welcome message for the user.

Please see the example below for the code.

def DoSomething():
    name = input("What is your name?")
    print("Hi Welcome", name)


DoSomething()

Code Blocks And Scope – Python Intermediate Series – Subroutines

In the code above, two lines of code have an indent. This works like loops and selection (if/elif/else). The indented code is all part of the first non-indented line above it.

The first line defines the subroutine, and then all the indented lines are part of the subroutine. Copy and paste the code below into an IDE; it should give you warnings like the image.

list_data = []


def user_input():
    global list_data
    name = input("Hi, What is your name?")
    list_data.append(name)
    
print(name)
python subroutine scope error
python subroutine scope error

In the code and image above, the variable ‘name’ is within the subroutine ‘user_input’ and is not accessible to code outside the subroutine. This name of the concept is scope, and all indented lines form a ‘code block’ for the subroutine. The IDE knows the variable is not accessible in the print statement, so it underlines it with an error. The colour of the underline will vary by IDE and user settings.

Variables not contained in a subroutine or other code block, such as a loop, are in ‘global scope’. Code inside a subroutine can read global variables. However, to write to them, the word ‘global’ combined with the variable name must be in the subroutine.

Passing Parameters

We can pass data into a subroutine and then use that data inside the subroutine. See the code below.

def greeting(user_name):
    print("Hi", user_name, "I love your name!")


name = input("Hi, What is your name?")

greeting(name)

In the above code, the first line lines define a subroutine called ‘greeting’. It has one parameter (a bit of data passed into the subroutine). Inside the code block of the subroutine, it prints out a message that contains the contents of ‘user_name’. ‘user_name’ is a variable that is only accessible inside the subroutine’s code block. The subroutine will not execute until it is another bit of code calls it.

The program starts executing in the first line of code under the subroutine. First, the program asks the user for their name and assigns it to ‘name’. Second, it passes the variable ‘name’ into the subroutine. Notice that the variable names in the parameters differ from the global scope variables. This is to make it clear which name is accessible and where.

Passing Multiple Parameters

It is possible to pass multiple parameters into a subroutine; see the code below.

name = input("Hi, What is your name?")
age = int(input("How old are you"))


def greeting(user_name, user_age):
    print("Hi", user_name, "you are", user_age)


greeting(name, age)

The above code asks for the user’s name and age and then passes both into the subroutine. Notice how in both cases, the variable name in the parameters differs but is clearly relatable variable we pass in. Understanding what is for the compiler and what is for humans is essential.

The compiler understands the order of the parameters. If you pass them incorrectly, it will still run (in this case). However, the output will be wrong. Making the matches between the variable names clear is to help humans read the code.

Returning Values – Python Intermediate Series – Subroutines

In addition to passing data into a subroutine, we can also return data. See the code below.

name = input("Hi, What is your name?")
age = int(input("How old are you?"))
year = int(input("What year is it?"))


def calculate_year_born(user_age, current_year):
    year_born = current_year - user_age
    return year_born


dob = calculate_year_born(age, year)

print("Hi", name, "you are", age, "and were born in", dob)

Firstly, notice how the subroutine sits in the middle of other code in this example. I did this deliberately to clarify an important point., subroutines do not need to be at the top of the code. However, a subroutine must be above the code that calls it.

Secondly, The code above passes the users’ age and years into the subroutine. Thirdly, inside the code block, it calculates the user’s year of birth (this is not an arcuate calculation, it takes no account of the current date or if they have had their birthday this year). Fourthly, the result is assigned to a new variable inside the subroutine. Next, the variable gets returned.

Finally, the returned value is assigned to the variable ‘dob’. Which is then used in the following ‘print’ statement.

Nested Subroutines (Subroutines inside Subroutines)

Nesting subroutines is a very powerful way of building up Python programs. The code below is an example of the concept. The ‘calculate_year_born’ subroutine is called inside the ‘user_input’ subroutine.

listData = []


def user_input():
    global listData
    name = input("Hi, what is your name")
    age = int(input("How old are you"))
    year = int(input("What year is it"))
    dob = calculate_year_born(age, year)


def calculate_year_born(user_age, current_year):
    year_born = current_year - user_age
    return year_born

Building A bigger Program – Python Intermediate Series – Subroutines

So far, the subroutines we have looked at could be created easily without a subroutine. Their real power comes when an operation must be done multiple times. Let us start with a diagram showing the top level of a program that takes user input.

Top Level

python take user input subroutine
python take_user_input subroutine

The code for this subroutine is as follows:

listData = []


def take_input():
    global listData
    #more data here but shown lower down

take_input()

1st Level Subroutines

Take User Input

First, it defines a variable to store data and then assigns an empty list with global scope. Then it defines a subroutine ‘take_input’. That subroutine executes at the bottom of the example above. Inside the subroutine, write access is given to the global variable ‘listData’; a Boolean variable ‘more’ is declared and true assigned. Next, there is a while loop which contains two more subroutine calls.

For the code to run, those subroutines will need to be declared. However, we add them one bit at a time to see how it builds into a program. First, look at the diagram below that shows the subroutine in the code above.

take user input subroutine
Take user input subroutine.
def take_input():
    global listData
    more = True
    while more:
        user_input()
        more = more_input()

The subroutine above gives write access to the global variable ‘moreData’ and sets a Boolean variable ‘more’ to True. Next, a while loop continues while ‘more’ remains true. Each loop takes a single user input and tests to see if the user wishes to enter more names. Both lines of code inside the while loop are subroutines. The first returns no value, but the second does. It then assigns the return value from the second subroutine to ‘more.’ before its checks the status of ‘more’ as the conditional in the while loop.

2nd Level Subroutines

User Input

Nested subroutine
Nested subroutine
def user_input():
    global listData
    name = input("Hi, what is your name")
    age = int(input("How old are you"))
    year = int(input("What year is it"))
    dob = calculate_year_born(age, year)
    data = concatenate_output(name, age, dob)
    listData.append(data)

First, the code gives write access to the global variable ‘listData’. Next, the user enters three data bits: their name, age and the current year.

After the data collection, it calculates the user’s birth year, passing in their age and the current year to the subroutine ‘calculate_year_born’. The return value is assigned to a variable ‘dob’.

Next, the code creates a single string using the ‘conctenate_output’ subroutine. It then passes the user’s name, age and birth year into the subroutine. The return value is then assigned to ‘data’.

Finally, the value of ‘data’ is appended to the end of the variable ‘listData’.

More Input

def more_input():
    yes_no = input("Would you like to enter another name (y/n)")
    more = bool(yes_no.lower() == "y")
    return more

Firstly, the code asks the user if they want to enter another name. Then their response is assigned to the variable ‘yes_no.’

Secondly, it creates a boolean value that tests whether the user input was ‘Y’ or ‘y’. If the user entered ‘Y’ or ‘y’, the value is True. The Boolean checks for ‘y’ but converts text to lowercase before the test. Any other input from the user will mean the value is False. Finally, it returns the Boolean value.

3rd Level Subroutines

Calculate Year Born

def calculate_year_born(user_age, current_year):
    year_born = current_year - user_age
    return year_born

This code is exactly the same as the example near the start of this post. It takes two parameters, the users age and the current year, calculates the year they were born and returns the result.

Concatenate the output

def concatenate_output(user_name, user_age, year_born):
    data = "User: " + user_name + " is " + str(user_age) + " and was born in " + str(year_born)
    return data

The code above takes in three parameters and then concatenates (joins) them into a single string with additional text to form a coherent sentence. It then returns the new string.

Final Combined Code

listData = []


def user_input():
    global listData
    name = input("Hi, what is your name")
    age = int(input("How old are you"))
    year = int(input("What year is it"))
    dob = calculate_year_born(age, year)
    data = concatenate_output(name, age, dob)
    listData.append(data)


def concatenate_output(user_name, user_age, year_born):
    data = "User: " + user_name + " is " + str(user_age) + " and was born in " + str(year_born)
    return data


def calculate_year_born(user_age, current_year):
    year_born = current_year - user_age
    return year_born


def more_input():
    yes_no = input("Would you like to enter another name (y/n)")
    more = bool(yes_no.lower() == "y")
    return more


def take_input():
    global listData
    more = True
    while more:
        user_input()
        more = more_input()


take_input()

Video Version – Python Intermediate Series – Subroutines

Related Articles – Python Intermediate Series – Subroutines

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *