GeekTrainer

Musings of a trainer of geeks.

Python Type Hints

I was on a community call on the Microsoft Python Discord channel when I was asked what my favorite new feature for Python was. My answer was immediate - “Type hints, type hints, type hints”. I find questions like this make for great blog posts, so let’s give it a whirl!

The problem

Before we get into type hints and why they’re so amazing, let’s explore the problem space. Let’s say I’ve created the following function:

def display_message(text):
    print(text)

At this point everything is just fine. It’s a small function, does one thing, and it’s pretty obvious contextually and onomatopoetically that text is a string. But this isn’t always the case - names may not be clear, functions more complex, or other challenges may obscure the actual data type. Not knowing what a parameter type is causes all sorts of challenges.

When I’m calling a function, unclear parameter types can make it more difficult to figure out both what the function does and how to use it. Functions with parameter names which aren’t clear, or maybe use a different naming scheme than I am, it becomes tricky.

Return types are also confusing. Because Python is a weakly typed language, the return type can’t always be inferred by the code. If you’re calling out to another library, or different logic paths return different types, you’re likely not going to have a good sense of what’s being returned - or if anything is being returned!

While some of this can be overcome with docstrings, the developer tool’s support is still going to be limited. You’ll be able to see the data types documented, but the editor won’t be able to offer autocomplete or other help.

Finally, creating functions which are used by a framework are more difficult than they should be, as I don’t always know the data type being passed in. While I can check the docs, that’s not near as convenient as having the editor offer me intellisense. Take the following view example from Django:

def index(request):
    # Logic here

The above code is a view function which accepts a HttpRequest object as a parameter. Unfortunately my editor doesn’t know what request is, and won’t be able to offer any support. I’m stuck having the documentation open at all times.

Introducing type hints

So, what are type hints? As the name implies, they are hints about the data types of variables, parameters and return types. While they are not enforced by the runtime, they can be used by linters, editors and other tools - which is really where the support matters the most. If you’re using type hints in an editor (say like Visual Studio Code) you’ll notice you get intellisense and autocomplete, and inline documentation about data types.

Using type hints for primitive types

Support for type hints for primitive types (such as strings and numbers) is already built-in. All you have to do is use the syntax!

To indicate a data type for a parameter, you place a colon after the parameter name and then the data type:

def display_name(name:str):
    # name is now a string

If you add the above code to a Python file in a code editor, and then use the name parameter you’ll see the editor knows name is a string!

To indicate a return type, you add -> to the end of the function declaration:

def get_message(name:str, age:int) -> str:
    return f'{name} is {age}'

Without having to add any additional imports, you can work with str, int, float, bool and a host of others.

Using type hints for classes

Earlier we highlighted the HttpRequest object from Django. If we want to update the index function to indicate the data type for request, we can import HttpRequest like we normally would, and then use the syntax we’ve seen:

from django.http import HttpRequest

def index(request: HttpRequest):
    # We now know what request is!

This works for any class! No additional code is needed.

Working with complex types

The typing module has quite a bit of power which you can explore. I want to highlight how to create typed lists:

from typing import List

names: List[str] = []
names.append('Christopher')
names.append('Tamiko')

for name in names:
    print(name)

If you add this code to a Python file, you’ll notice your editor will highlight the fact names can only store strings. Your editor will even carry this through into the for loop; you’ll notice IntelliSense for the name variable inside there.

Conclusion

Bringing this all together, type hints help you statically type your variables in Python. This can make it easier to both create and call functions (the primary place where I like using type hints), but also down to variables as well. While certainly not required, I would definitely recommend incorporating type hints into your code!