Python Arena
Step 3 of 3

Passing data between functions

A program made of several functions needs to move data between them. The module on strings and lists showed one way: through parameters and return values. Now that you know global, there's a second way: global variables that all the functions read and change. The first way is almost always the better one.

With parameters and return values, each function is an independent whole. What it needs comes in as arguments, and what it produces goes out with return. You can read the function and understand it without the rest of the program, test it by calling it with different arguments, and use it in another program. When many functions change the same global variables, any of them can change the data at any time, and finding which one caused a wrong value means reading all of them.

Here is a program in three functions. The main program keeps the data, the list temperatures, and hands it to each function that needs it:

def read_temperatures(days):
    temperatures = []
    for day in range(1, days + 1):
        temperatures.append(int(input(f"Day {day}: ")))
    return temperatures


def warm_days(temperatures):
    count = 0
    for temperature in temperatures:
        if temperature >= 20:
            count += 1
    return count


def report(temperatures):
    print("Highest:", max(temperatures))
    print("Lowest:", min(temperatures))
    print("Warm days:", warm_days(temperatures))


temperatures = read_temperatures(4)
report(temperatures)
Input
18
22
25
17
Output
Day 1: 18
Day 2: 22
Day 3: 25
Day 4: 17
Highest: 25
Lowest: 17
Warm days: 2
  • read_temperatures creates the list and returns it. The main program stores it in its own variable.
  • report gets the list as an argument, and passes it on to warm_days, which returns a number.
  • None of the functions uses a global variable. The parameter temperatures in each function is a local name for the list the caller gave it.

A main function

You can go one step further and put the main program in a function too, usually called main. Then the program has no global variables at all, and the line under if __name__ == "__main__": only starts it:

def main():
    temperatures = read_temperatures(4)
    report(temperatures)


if __name__ == "__main__":
    main()

Now temperatures is a local variable of main. The only way other functions can get it is as an argument, which is exactly the point.

A list is passed, not copied

One thing to remember from the module on references: a list given as an argument is the same list, not a copy. If a function changes it with append or by assigning to an index, the caller sees the change. That's useful when changing the list is the function's job. When it isn't, a function should build a new list and return it.

Your task

Challenge 1 of 3

This program works, but its functions share the global list words. Change it so that read_words() creates the list and returns it, and longest(words) gets the list as a parameter and returns the longest word (the first of them, if several are as long). The main program prints the result. Don't use global. A run looks like this:

Word: tree
Word: elephant
Word: cat
Word: end
Longest: elephant

Challenge 2

What does this program print? Type each line it prints.

Challenge 3

The file of a month's expenses has a category and an amount on each line (category;amount), and a category can appear on many lines. The starter code has the main function ready. Write the two functions it uses:

  • read_expenses(filename) returns a dictionary from each category to its total amount, in the order the categories first appear in the file;
  • print_report(expenses) gets such a dictionary and prints each category and its total, then the total of everything.

With this may.csv

food;120
rent;800
food;125
fun;60

a run looks like this:

File: may.csv
food: 245
rent: 800
fun: 60
Total: 1105