Python Type Hints — Old and new ways to write the same types
As type hints have evolved, Python has added simpler, more succinct syntaxes. But you still need to know the older forms, since Mypy uses them when reporting types.
Union types
A union type combines several types, expressing that a value may be any one of those types. PEP 484 introduced type hints and defined Union to express union types, allowing you to write:
Later, PEP 604 added the | operator for union syntax. This allows you to skip an import of Union and instead write:
This feature was added in Python 3.10. But you can use it from Python 3.7, if you use Mypy 0.800+ and postponed evaluations with from __future__ import annotations .
Optional types
An optional type is basically a union between a type and None . The value is either there, or None .
The first way to write this is with Union :
Since optional types are very common, the original type hint PEP 484 added a shortcut, typing.Optional :
But since PEP 604, it’s preferable to use the neat union syntax:
Lists and other builtin containers
When type hints were first introduced, they avoided disruption as much as possible. To avoid altering common types, the typing module introduced container types for builtin types. For example, you can represent a list of int s with typing.List :
PEP 585 later merged that capability back onto the builtin types. This allows you to write:
- Other builtin container types: dict , tuple , set , and frozenset
- The base type, type
- Many abstract base classes in the collections.abc module, like Callable , Iterable , and Generator
- Types from the collections module like defaultdict and deque
- Regex types from the re module: Pattern and Match
You can see the full list in the PEP.
These changes were added in Python 3.9. But again, you can use them from Python 3.7, if you use Mypy 0.800+ and postponed evaluations with from __future__ import annotations .
pyupgrade can help you adopt the new syntax
The pyupgrade tool automatically rewrites code to use the latest Python syntax. It has support for adopting all the above new syntax, including changing imports. Check out my previous post for more details.
Mypy reports using old syntax
Update (2023-06-26): Mypy 1.4.0+ now use newer syntaxes, as covered in my later post.
It’s nice to use the latest and greatest syntax when writing your code. But when Mypy reports types, it often still uses the old syntax (at least as of Mypy 0.982), so you still need to know how to read it.
Take this combined example, using reveal_type() to report the types:
- The union types use Union instead of |
- The builtin types are all prefixed with builtins
- list retains its new syntax, instead of using typing.List
Mypy can also report Optional , e.g. for this misassignment:
So, at least for now, you need to know the old syntax to understand Mypy’s output.
I’d like to see Mypy updated to report types in the newer, shorter forms. I couldn’t find a specific issue, but I would guess there’s no update right now since Mypy supports older Python versions (when not using __future__.annotations ). Also I saw there are some lingering edge cases with the PEP 604 union syntax.
Fin
May your type hints be succinct and your understanding comprehensive,
Learn how to make your tests run quickly in my book Speed Up Your Django Tests.
One summary email a week, no spam, I pinky promise.
Tags: mypy, python © 2022 All rights reserved. Code samples are public domain unless otherwise noted.