After working with Go for a while, one of the biggest drawbacks to Python for me is that the types of parameters to functions and methods are completely opaque without good documentation.

For example, let’s take this silly function right here:

def my_func(thing1, thing2):
    print(thing1 + thing2)

This function will happily accept strings or ints (or floats, for that matter) as input and depending on the type, will do completely separate things!

Here’s an example of the same problem which is less forgiving. If you provide strings to this function, the Python interpreter will throw a TypeError exception.

def bad_func(*foo):
    result = 0.0

    for i in foo:
        result += i

    print(result)

The problem is that it can be completely non-obvious what type of data a given parameter on a given function or method is expecting without closely inspecting the code.

That’s why Google’s Python style guidelines mandates such comprehensive method and function documentation.

But thankfully, Python 3.5 introduced type hints which makes this whole situation much better. Type hints are not enforced by the interpreter at runtime, but you can use tools like mypy to examine your code for problems before you ship it.

Here’s the first code example modified to have type hints to indicate that each parameter should be of type string.

def my_func(thing1: str, thing2: str):
    print(thing1 + thing2)

And here’s the second code example modified with type hints. Our last call to bad_func() can be detected by mypy and called out as an error:

#!/usr/bin/env python3

from typing import Union

def bad_func(*foo: Union[int, float]):

    result = 0.0

    for i in foo:
        result += i

    print(result)

bad_func(1, 2, 3, 4, 20.2)
# bad_func("foo", "bar")

What if you want to use type hints on a parameter which has a default value?

Here’s how!

def my_func(thing1: str, thing2: str = "look, a default!"):
    print(thing1 + thing2)

More info can be found in PEP 484 and at RealPython.com.