Part 6: Creating functions — Python Värmland

Python Värmland

Part 6: Creating functions

The short version - for experienced programmers

Functions are defined using the def keyword in Python.

def my_function(arg1, arg2):
    print(f"{arg1} + {arg2} = {arg1 + arg2}")

    # If you don't explicitly return anything, the special
    # value None will be returned implicitly.
    return arg1 + arg2

The full version - for beginner programmers

Answer to the exercise in Part 5

Here's one possible answer to the exercise from Part 5.

# Let's call our list 'items', since calling it
# 'list' is a bad idea.

items = []

user_input = ""

while user_input != "q":

    if len(items) == 0:
        print("The list is empty.")
    else:
        item_num = 0

        for item in items:
            print(f"{item_num}: {item}")
            item_num += 1

    # Just print an empty line
    print()
    user_input = input("Add, delete or quit (a/d/q)? ")

    if user_input == "a":
        new_item = input("What should I add? ")
        items.append(new_item)

    if user_input == "d":
        if len(items) == 0:
            print("There is nothing to delete.")
        else:
            delete_index = input("Enter number of item: ")
            delete_index = int(delete_index)
            del items[delete_index]

print("Goodbye!")

Functions

We've already used some of the functions that come ready-made with python, such as print, input and len. But you can also make functions on your own. Once you've seen how to make one, you'll soon understand what they are and what they're for. So let's dive in and make the simplest possible function we can.

def say_hello():
    print("Hello!")

The word def is used when creating a function. After it follows the name of the function you want to create (in this case say_hello), and then the name of its arguments (if any - in this case, there are none) inside parentheses and finally a colon. If there are no arguments, you still need the parentheses, you don't just put anything between them. Then, the entire contents of the function must be indented, just like with loops (which means that loops inside functions are at least doubly indented - once for being inside a function, and once for being a loop).

After this, we can then call (read: use) the function by typing:

say_hello()

And the not very surprising result will be:

Hello!

Functions with arguments

Okay. That function was almost entirely pointless, let's make one that's a little more useful. Like this:

def calculate_area(height, width):
    area = height * width
    return area

This creates a function called calculate_area. Unlike our previous say_hello function, this one takes two arguments - height and width. Using these, it calculates an area by simply multiplying them as one does. Then, we return the result. That means that the value from the area variable is sent back to where ever it was called from. This means that we can now do this:

area = calculate_area(10, 5)
print(area)

And we will get the following:

50

If we don't want to keep the area by storing it in the area variable - if we only want to print it, and that's it - then we can shorten it like this:

print(calculate_area(10, 5))

In that case, the 50 which are returned from calculate_area(10, 5) are sent directly - as an argument - to the print function.

How about a function that's actually useful?

The functions we've made so far aren't really that useful - so let's make one that is. We will now rewrite and extend the list_maker.py program that we made in Part 5 using functions to make it better. Let's start by making a function that will let us print the list, with a number next to each item.

There is one think that we must keep in mind. In the previous list_maker.py from Part 5, the numbered list of items we printed on the screen started with 0, just like the list starts with items[0]. That makes it a bit easier on the programmer - the number we print, is the same as the one the list uses internally. But for the user, this becomes a bit counter-intuitive; we expect numbered lists to start with 1 rather than 0. Because of this, we will make things work the way a human would expect this time. The first item in the list will still be item[0] (we have no other choice - that's how Python works), but when we show it on the screen, it will be called number 1. And subsequently, item[1], the second item, will be called number 2 on the screen, and so on. We must keep this in mind - we must always subtract 1 from the number we show on the screen, to get the proper list index (read: the number between [ and ] in item[0]).

Open IDLE, select File and then New file. Then type the follwing into our new file:

def display_items(items):
    if len(items) == 0:
        print("The list is empty.")
        return

    item_num = 1
    for item in items:
        print(f"{item_num}. {item}")
        item_num += 1

Save it (Control-s) giving it the name list_maker2.py - but there is no point in running it yet. If you try, nothing will happen. That's because we have "defined" (read: written) the function, but we haven't "called" (read: used) it yet. That comes later - we need more functions first.

This function starts by checking if there are in fact any items in the list - if there aren't, then there's no point in trying to print it. Instead, it will print The list is empty in such cases and then return. Again, the return statement exits the function, going back to where we were when we called it.

Now we can use this function every time we want to print a list. And if we want to change how lists are printed, we only have to change it once - in this function. If we instead had copied and pasted the code each time we wanted to print a list, we would have to change each copy every time we wanted to change how lists are printed. This is an important concept in programming: always try to avoid duplicating code. Having duplicates makes it harder to maintain your programs, because there is more to maintain.

Okay. So now we can print our list, using the display_items function we just wrote. We just need another function now, which serves as the "main loop" of our program. This function will have a loop that does the following:

The loop exits automatically when the player chooses to quit, since the condition to continue the while loop is that they haven't chosen to quit. Add this function to the file:

def main_loop():
    # This, [], is an empty list. We start with that.
    items = []

    user_input = ""

    while user_input != "q":
        display_items(items)

        user_input = input("Add item or quit (a/q)? ")

        if user_input == "a":
            new_item = input("What should I add? ")
            items.append(new_item)

We now have both the functions that we need (for now) - one that displays the list, and one which loops around until the user chooses to quit.

There's still one final thing that our program needs before it will work. And that is - we need to call (read: tell our program to start) the main_loop function. So, at the end of our file, add two blank lines (that's customary between functions and other lines in Python), and then just this line:

main_loop()

This line calls the main_loop function (which in turn calls our display_items function). It is important that this line is below the function itself, because otherwise Python will be like "What is this main_loop function of which you speak?" Python needs to have seen that function before we can call it.

That's all we need to run our new function-based list_maker2.py program. For clarity, here it is again in its entirety:

def display_items(items):
    if len(items) == 0:
        print("The list is empty.")
        return

    item_num = 1
    for item in items:
        print(f"{item_num}. {item}")
        item_num += 1


def main_loop():
    # This, [], is an empty list. We start with that.
    items = []

    user_input = ""

    while user_input != "q":
        display_items(items)

        user_input = input("Add item or quit (a/q)? ")

        if user_input == "a":
            new_item = input("What should I add? ")
            items.append(new_item)


main_loop()

Run it (F5), and make sure that it works.

A slightly more complex function - select_item

It's time to add some more functionality to our program. We also want to be able to delete items from our list. When the user presses d for delete, we want to ask them which item they want to delete. This "selecting an item from the list" business sounds like something that would be great to put into a function. Because in the future, we might want to add more functionality to our program, which also requires that the user select an item from the list. Therefore, it's a good idea to put the "select an item from the list" code in a function which we can easily reuse.

So, we have decided that we need a select_item function. This function will be a little more complex than our other functions, so we should probably give it some thought before we start writing it.

It's a good idea to decide on what requirements we have on functions. In this case, the following is a reasonable list of requirements:

These requirements means that our function will need to have access to the list (in order to know how many items it has, and thus which inputs are valid), and also the prompt we wish to use. Therefore, we simply send the list and a prompt to the function as arguments when we call it. Using this information, we can write the following function (type it in just before the main_loop() call at the end of the list_maker2.py file, separated by two blank lines):

def select_item(items, prompt):
    # num_items == how many items are in the list
    num_items = len(items)

    # Now we want to give the user several tries
    # to make a valid choice. Therefore, we need
    # a loop.
    while True:
        item_num = input(prompt)
        item_num = int(item_num)

        # We check if the user's number is valid.
        if item_num < 1 or item_num > num_items:
            # The user's number is not valid.
            print(f"Valid numbers are 1 to {num_items}")
        else:
            # The user's number is valid, so let's return it.
            return item_num - 1

In our main_loop function, we need to change the line that used to say "Add item, or quit (a/q)? " to also mention our new "remove" option, and then we need to add a few lines at the end which will remove the item the user has selected. After we've made our changes, the function should look like this:

def main_loop():
    # This, [], is an empty list. We start with that.
    items = []

    user_input = ""

    while user_input != "q":
        display_items(items)

        # This line is changed - "remove" has been added
        user_input = input("Add, remove or quit (a/r/q)? ")

        if user_input == "a":
            new_item = input("What should I add? ")
            items.append(new_item)

        # The lines below this one are new:
        if user_input == "r":
            if len(items) == 0:
                print("There is nothing to remove.")
                continue

            index = select_item(items, "Remove which item? ")
            del items[index]

In the new lines at the end of the function, we check if the user has entered r for "remove". If so, we check if the list is empty (we check if the length of the list is zero). In that case, there is nothing to delete, so we say as much. Then, we "continue", which is something new we haven't seen before. What continue means is that when Python reaches this line, it will continue with the next run-through of the while loop. In other words, continue makes sure that the lines below it are skipped if the list is empty (because then there are no items to delete, so no use in trying).

Exercise

Your exercise this time is to add another thing the user can do to our list_maker2.py program: editing items.

  1. There should be a new option, e for edit.
  2. When the user chooses this option, they should be asked to select which item to edit.
  3. They should then be asked for a new item, to replace the one they selected.
  4. The selected item should be changed accordingly.

Try to use existing function(s) when you can, to avoid duplicating work. As always, you will find a suggested solution in the next part of this tutorial.

Previous: Part 5: Lists and for loops | Next: Coming soon ™ | Index

Understood
This website is using cookies. More details