Python Arena
Step 2 of 6

Trying out your functions

In the last module, you tried out a function by adding a call under its definition. Such calls have a catch. The checks of a function task load your program, the way Python loads a module, and then call your function themselves, with arguments of their own. Loading runs all the code at the top level of the file, so your own calls run too: they print extra lines before each check, and an input() among them stops the check, because the check types no input.

So the code that tries out your functions needs a place that runs when you run the program, but not when the checks load it. That place is a block at the end of the file:

def stars(count):
    print("*" * count)


if __name__ == "__main__":
    stars(3)
    stars(5)
Output
***
*****

if __name__ == "__main__": is a condition, and the code indented under it is called the main block. When you run the file, the condition is true and the block runs. When a check loads the file to call your function, the condition is false and the block is skipped. Module 31 explains how that works. For now, remember the rule: code that tries out your functions by hand goes under if __name__ == "__main__":. (A program that only uses its own functions, like most examples in the lessons, can call them at the top level: no check calls its functions on their own.)

From now on, the starter code of a function task has a main block with a call or two:

def stars(count):
    pass


if __name__ == "__main__":
    stars(3)

As before, pass holds the place of the body until you write it. Change the calls in the main block as much as you like: the checks ignore them. Run with my input runs your file as a program, main block included.

When a check fails

A failing check shows the call it made. The quickest way to see what goes wrong is often to make the same call yourself: copy it into the main block and run the program. Then you get Python's whole error message:

def initial(name):
    print(name[0] + ".")


if __name__ == "__main__":
    initial("Grace")
    initial("")
Output
G.
Python stops with
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    initial("")
    ~~~~~~~^^^^
  File "main.py", line 2, in initial
    print(name[0] + ".")
          ~~~~^^^
IndexError: string index out of range

As you saw in the last module, a traceback through a function has two parts. Read it from the bottom up: the last line names the error, the part above it shows the line in the function where it happened (line 2, in initial), and above that is the call that led there (line 7). Here the call gave an empty string, which has no character at index 0, so the function needs to handle that case on its own.

Debugging prints

Some bugs don't stop the program: it just prints the wrong thing. To see what happens inside a function, print its variables at the spot you want to see. This function should print the sum of the numbers from 1 to limit, but for 4 it prints 6 instead of 10:

def sum_up_to(limit):
    total = 0
    number = 1
    while number < limit:
        total += number
        print("number:", number, "total:", total)
        number += 1
    print("Sum:", total)


if __name__ == "__main__":
    sum_up_to(4)
Output
number: 1 total: 1
number: 2 total: 3
number: 3 total: 6
Sum: 6

The debugging print shows that the loop stops after 3, so the 4 is never added. The condition should be number <= limit. Once the bug is fixed, remove the debugging print: the checks compare everything your function prints.

Your task

Challenge 1 of 3

The function banner works, but the calls that try it out are at the top level, so they print extra lines whenever the checks load the program. Move the two calls under if __name__ == "__main__": at the end of the file. Run the program, and it prints:

==
Hi
==
=======
Welcome
=======

Challenge 2

The function middle_letter(word) prints the letter in the middle of a word (for a word of even length, the second of the two middle letters). A check calls middle_letter("") and the program crashes. Make the function print (empty) when the word is empty, and the middle letter otherwise. For example, middle_letter("cat") prints:

a

Challenge 3

The function countdown(start) should count down from start to 1, one number per line, and then print Go!. It forgets the last number. Find the bug (a debugging print helps) and fix it. countdown(3) should print:

3
2
1
Go!