To use type hints in a fully backwards-compatible way, you will need to...
- Always use the comment-based syntax: Python 2 does not support function annotations; Python 3.0-3.5 do not support variable annotations.
- Install the backport of the typing module when using Python 2.7 and 3.0 - 3.4. The typing module was added to the standard library in Python 3.5 and must be pip-installed for earlier versions of Python.
One additional complication is that the typing module was updated several times with new types since it was added to the standard library in Python 3.5.0 -- types like ClassVar, Deque, Protocol, Text, Type, to name just a few.
If you want to use those types and still support Python 3.5 and 3.6, additionally install the typing_extensions module. You can find a full list of backported types on the github repo.
Basically, if you want to use any of the types listed in the github repo linked above, and support Python 3.5.0 - 3.6.x, always import them from typing_extensions
instead of from typing
.
Some additional details and caveats that you may or may not care about:
About typing_extensions
:
If you plan on using typing_extensions
, also pay careful attention if you need to support Python 3.5.0 - 3.5.2. The typing module went through several, often substantial, internal changes since it was first released in Python 3.5.0.
The typing_extension
module tries to bridge between these different internal APIs in a sane way, but there's always the chance that something was overlooked. The latest minor versions of Python 3.5 and Python 3.6 are much more up-to-date though, and so are far less likely to have issues.
(You might also be able to get away without using typing_extensions
if you want to support only the latest minor versions of Python 3.5 and 3.6: several of the types that were missing in Python 3.5.0 and Python 3.6.0 were added later on. But it's honestly hard to keep track of what was added when, so it might be safer to just default to using typing_extensions and not worry about it.)
About mypy:
If want to use mypy, keep in mind that mypy can be run using only non EOL'd versions of Python 3. So, at time of writing, Python 3.4+.
However, mypy itself can be used to analyze Python 2.7+ code.
About typeshed and Python 3.0 - 3.2:
Mypy, and most other PEP 484-compliant type checking tools, rely on typeshed, a collection of type annotations for the standard library and popular 3rd party libraries.
Typeshed keeps track of when functions and classes were added to the standard library. That way, you can ask tools like mypy to make sure your code works with specific versions of Python and that you didn't accidentally import anything from the future.
However, typeshed only keeps track of this info for Python 2.7 and 3.3+. So, you need to be careful if you're targeting specifically Python 3.0 - 3.2.
About unicode_literals and mypy/typeshed:
Some people recommend using unicode_literals as a technique to help with Python 2/3 compatibility.
However, I believe using unicode_literals causes a number of issues with either typeshed or mypy. I forget the exact details, but the upshot is that you're probably better off not using it (at least for the time being).
Instead, avoid unicode-related issues by using the type system to your advantage. Specifically:
- Use
typing.Text
when something MUST be unicode. This type is aliased to unicode
in Python 2 and str
in Python 3.
- Use
bytes
(or maybe bytearray
?) when something MUST be bytes. Be sure to keep in mind that the bytes
behaves slightly differently between Python 2 and 3.
- Use
str
when that a value should be whatever str
means for that particular version of Python.
If you need to write a function that needs to work with multiple kinds of strings, you can do so with careful use of Union
or AnyStr
.