Introduced since Python 3.5, Python’s typing module attempts to provide a way of hinting types to help static type checkers and linters accurately predict errors.
Due to Python having to determine the type of objects during run-time, it sometimes gets very hard for developers to find out what exactly is going on in the code.
Even external type checkers like PyCharm IDE do not produce the best results; on average only predicting errors correctly about 50% of the time, according to this answer on StackOverflow.
Python attempts to mitigate this problem by introducing what is known as type hinting (type annotation) to help external type checkers identify any errors. This is a good way for the programmer to hint the type of the object(s) being used, during compilation time itself and ensure that the type checkers work correctly.
This makes Python code much more readable and robust as well, to other readers!
NOTE: This does not do actual type checking at compile time. If the actual object returned was not of the same type as hinted, there will be no compilation error. This is why we use external type checkers, such as mypy to identify any type errors.
For using the typing
module effectively, it is recommended that you use an external type checker/linter to check for static type matching. One of the most widely used type checkers in use for Python is mypy, so I recommend that you install it before reading the rest of the article.
We have already covered the basics of type checking in Python. You can go through this article first.
We will be using mypy
as the static type checker in this article, which can be installed by:
You can run mypy
to any Python file to check if the types match. This is as if you are ‘compiling’ Python code.
After debugging errors, you can run the program normally using:
Now that we have our prerequisites covered, let’s try to use some of the module’s features.
We can annotate a function to specify its return type and the types of its parameters.
This informs the type checker (mypy
in my case) that we have a function print_list()
, that will take a list
as an argument and return None
.
Let’s run this on our type checker mypy
first:
As expected, we get an error; since the line #5 has the argument as an int
, rather than a list
.
Since Python 3.6, we can also annotate the types of variables, mentioning the type. But this is not compulsory if you want the type of a variable to change before the function returns.
Output of mypy:
This is the recommended way to use mypy
, first providing type annotations, before using the type checker.
The typing
module provides us with Type Aliases, which is defined by assigning a type to the alias.
Output
In the above snippet, Vector
is an alias, which stands for a list of floating point values. We can type hint at an alias, which is what the above program is doing.
The complete list of acceptable aliases is given here.
Let’s look at one more example, which checks every key:value pair in a dictionary and check if they match the name:email format.
Output from mypy
Here, we get a static compile time error in mypy
, since the name
parameter on our second dictionary is an integer (123). Thus, aliases are another way to enforce accurate type checking from mypy
.
We can use the NewType()
function to create new user defined types.
The static type checker will treat the new type as if it were a subclass of the original type. This is useful in helping catch logical errors.
Output from mypy
This is a special type, informing the static type checker (mypy
in my case) that every type is compatible with this keyword.
Consider our old print_list()
function, now accepting arguments of any type.
Now, there will be no errors when we run mypy
.
All functions without a return type or parameter types will implicitly default to using Any
.
You can thus use Any to mix up statically and dynamically typed code.
In this article, we have learned about the Python typing module, which is very useful in the context of type checking, allowing external type checkers like mypy
to accurately report any errors.
This provides us with a way to write statically typed code in Python, which is a dynamically typed language by design!
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.