I have previously talked about type narrowing with
Literal. In today’s post, we’ll look at
TypeGuarda new special type that allows us to create custom type narrowing functions.
TypeGuard was defined in PEP 647 and is available in Python 3.10+ or older versions from typing-extensions. Guido van Rossum added support to Mypy in version 0.900, which was published the day before.
Recall that type narrowing uses certain expressions to infer that, in a given block, a variable has a more restricted type than its definition. For example, using
from __future__ import annotations name: str | None if isinstance(name, str): # name must be 'str' ... else: # name must be None ...
Typecheckers, including Mypy, support a limited number of expressions such as
if isinstance(...). But the number of potentially type-restricting expressions is endless, especially for parameterized types like containers.
TypeGuard allows us to write any type expression and tell our type checker that it narrows them down.
A type narrowing function is one that takes at least one argument and returns
bool. Instead of denoting the return type as
True means the first argument is of type
False – No. Let’s take this example, adapted from PEP:
from __future__ import annotations from typing_extensions import TypeGuard def is_str_list(value: list[object]) -> TypeGuard[list[str]]: """Are all list items strings?""" return all(isinstance(x, str) for x in value) x: list[object] reveal_type(x) if is_str_list(x): reveal_type(x)
Trueif the given list contains only strings. We tell Mypy that it can narrow down the type
list[str] using return type
Running Mypy on this file, we see the following result call
$ mypy --strict example.py example.py:13: note: Revealed type is "builtins.list[builtins.object]" example.py:15: note: Revealed type is "builtins.list[builtins.str]"
The second note shows that Mypy knows that
x must be a list of strings in a block
if. This allows us to use the elements of the list as
str without any errors. Fine!
TypeGuard is flexible because it allows us to write arbitrary code to narrow expressions. True, it forces us to wrap even short expressions in separate functions, but this is often useful for code readability.
Since there are an infinite number of possible expressions, type checkers cannot confirm that the expressions we choose match the protected types. Therefore, the functions
TypeGuard should be written with care and tested thoroughly.
PEP 647 also shows common features
TypeVar, but when I tried the examples, I found that Mypy 0.901 doesn’t support them yet. For TypeGuard has several open issuesso it looks like Mypy can benefit from our input on their solution!
And keep your types well protected.
We invite everyone to an open lesson on the topic “Introduction to web development with Flask“. In this lesson, we will introduce you to the basics of Flask web development, as well as learn how to create and render page templates. Let’s try to create a Flask application, then create routes, and finally process various HTTP methods in Flask. Registration link.