Skip to content

Simple type checking examples

The most that you'll be doing with mypy is tweaking your code, fixing potential bugs, and changing your type annotations, to make mypy confident that your code is good. Let's look at a couple more code examples and see what mypy says about them.

Colors?

Let's write something to find a user's favorite color:

user_data = {
  'name': 'Mike Tyson',
  'color': 'red',
  'city': 'New York',
}

def get_favorite_color() -> str:
    favorite_color = user_data.get('color')
    return favorite_color

print("Tyson's favorite color is:", get_favorite_color())

The code runs fine, but mypy isn't happy yet. Why is that? The message is a bit cryptic:

mycode.py:9: error: Incompatible return value type (got "Optional[str]", expected "str")

Here's what mypy is saying: user_data.get(...) returns an Optional[str], but the function is supposed to return a str. What it's trying to say is: .get() can possibly return None. (We'll explore Optional in detail later.)

Though data is defined with a color property in it, the code could have changed the dictionary's contents, and removed the color property from inside it. Figuring out what value is and isn't inside a dictionary isn't possible without actually running the code, so mypy doesn't assume anything.

Essentially, mypy is concerned that user_data.get(...) could return None, which goes against your annotation of -> str.

To fix it, we can do multiple things, but for now, let's just assure mypy that we're always going to have color in the dictionary.

For that, let's add a runtime assertion:

user_data = {
  'name': 'Mike Tyson',
  'color': 'red',
  'city': 'New York',
}

def get_favorite_color() -> str:
    favorite_color = user_data.get('color')
    assert favorite_color is not None
    return favorite_color

print("Tyson's favorite color is:", get_favorite_color())

If favorite_color is ever None, Python will crash at runtime. So, mypy can guarantee that the color is a str. Mypy is convinced, and your types are perfectly valid.

There is another similar way to solve this, by not using .get(). I'll leave that for you to figure out.

An exercise

Try adding types to this code, and figure out if this code has any bugs:

def average(a, b, c):
    return (a + b + c) / 3

english, science, math = 75, 87, 90
avg_score = average(english, science, math)

def print_scorecard(score):
    print(f"Average score is: {score}")

if avg_score.is_integer():
    print_scorecard(int(avg_score))
else:
    print_scorecard(avg_score)