Python Arena
Step 2 of 3

Type hints

When you use a function from a module, you usually don't read its code. You read its first line, and that line should tell you what to pass and what you get back. That's what the type hints you met in part 4 are for, and with modules they earn their keep:

def with_tax(price: float, percent: int) -> float:
    return price * (1 + percent / 100)
  • price: float says the parameter price should be a float, and percent: int an integer.
  • -> float, between the parentheses and the colon, says what the function returns. A function that returns nothing has -> None.
  • A hint can also say what a list or a dictionary holds: list[int] is a list of integers, dict[str, int] a dictionary with string keys and integer values, and tuple[int, int] a tuple of two integers.

Here is a module with hints, and a program that uses it:

main.py
import scores

points = [7, 9, 4, 10]
print(scores.best(points))
print(scores.passed(points, 5))
scores.py
def best(points: list[int]) -> int:
    return max(points)


def passed(points: list[int], limit: int) -> int:
    count = 0
    for p in points:
        if p >= limit:
            count += 1
    return count
Output
10
3

Reading only the first lines of scores.py, you know that both functions want a list of integers and return an integer, and that passed also wants a limit. Editors such as Visual Studio Code show these first lines when you type a module's name and a dot, so you don't even need to open the module's file. A module is written once and used by many programs, often by other people, so these few words in its first lines save a lot of reading.

When the hint is ignored

Python itself doesn't check the hints, as you saw in part 4. A call with the wrong type runs, and goes wrong only where the value is used. With modules, that place is in another file, and the traceback has a line for each file on the way:

main.py
import money

print(money.with_tax("10", 24))
money.py
def with_tax(price: float, percent: int) -> float:
    return price * (1 + percent / 100)
Python stops with
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(money.with_tax("10", 24))
          ~~~~~~~~~~~~~~^^^^^^^^^^
  File "money.py", line 2, in with_tax
    return price * (1 + percent / 100)
           ~~~~~~^~~~~~~~~~~~~~~~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'

Read it from the bottom: the error happened in money.py, on line 2, where a string met a multiplication. The line above names the call in main.py that got there. The hint price: float told the caller what to pass; the caller passed the string "10". Separate checker programs (such as mypy) can find mistakes like this from the hints before the program runs, but Python doesn't.

Your task

Challenge 1 of 3

Add type hints to the function: its parameter is a list of floats, and it returns a float.

Challenge 2

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

Challenge 3

main.py is ready, and grades.py has the first lines of two functions, with type hints. Write their bodies:

  • grade(points: int) -> int returns the grade for 0 to 100 points: below 50 is 0, then each 10 points up is a grade higher (50 to 59 is 1, 60 to 69 is 2, and so on), and 90 or more is 5.
  • describe(grade: int) -> str returns "failed" for grade 0, "passed" for grades 1 and 2, "good" for 3 and 4, and "excellent" for 5.

For example:

Points: 85
Grade 4: good