Python is a dynamically typed language – I’m sure you know that. This makes it easy and fun for beginners, as there’s no need to think about data types. Still, static typing has some benefits. Today we’ll explore how to make Python as statically typed as possible.
Don’t feel like reading? Check out a video on the topic:
So, what’s the deal with dynamically typed languages? In a nutshell, it means there’s no code compilation, so the Python interpreter performs type checking as code runs. As a result, variable types are allowed to change throughout the application.
It may sound like an advantage, but it can lead to strange and hard-to-track errors as the code base gets larger.
On the other hand, statically typed languages perform type checks upon compilation (think C or Java). Further, they give you some feeling of safety, as you can immediately tell the type of parameter going into each function.
Just a quick disclaimer before we start – Python will always be a dynamically typed language. There’s nothing you can do to make it static as Java or C. PEP 484 introduced type hints, so we’ll have to work with that.
- Type hints
- Variable annotations
- Denoting more advanced data types
- Forcing type checking on runtime
Type hints are just that – hints. They show you which data type is expected, but nothing is stopping you from ignoring them. We’ll later explore how to force type checking by the Python interpreter, but let’s cover the basics first.
Let’s make an example without type hints. Below is a function designed to add two numbers and return the sum. Python being Python, we don’t have to specify data types for parameters nor for the return value:
The printed results from the function calls are 15, 15.3, and BobMark, respectively. To introduce the type hints, we have to do the following:
- For parameters – place the colon sign (:) right after the parameter name and specify the data type after
- For return value – place the arrow sign and the data type right after the parenthesis
Here’s how to add type hints to our
The function is a bit clearer to look at now, but we can still pass any data types – indicating that hints are just hints, not an obligation.
Here are type hint recommendations, according to PEP 8:
- Use normal rules for colons, that is, no space before and one space after a colon
- Use spaces around the = sign when combining an argument annotation with a default value
- Use spaces around the -> arrow
We’ll see how to force type checks later.
We can also provide type hints for variables. Once again, these are just hints and do not affect how the code runs.
Here’s a quick example of how to add type hints to variables:
age, or assigning no to
is_premium. Hints only indicate that you shouldn’t.
Denoting more advanced data types
Everything we covered thus far is great, but what if you want to declare a list of strings or a dictionary where both keys and values are strings?
That’s where the
typing module comes into play. With it, you can use any more complex data types, such as lists, dictionaries, and tuples. You can also declare your own data types, but that’s a bit out of the scope for today.
Let’s now use the
typing module to declare a list of names, and then a dictionary of emails, where each email belongs to a single name. In all cases, the data type is a string:
Forcing type checking on runtime
I’m not aware of any methods of forcing type checks in the Notebook environment – so we’ll switch to scripts. I’ve made a file called
static_typing.py, but feel free to name yours as you wish.
Before proceeding, we’ll have to install a library called
mypy. It is used to force type checks on runtime, just what we need. To install it, execute
pip install mypy from the Terminal.
We are now good to go. The
static_typing.py script contains the following code:
mypy, we can force the type checks. From the Terminal, execute the following:
As you can see, the program crashed. Just the behavior we wanted, as the function expects two integers, but we didn’t provide that data types in the function calls.
And that’s all you should know for starting out. Let’s wrap things up in the next section.
Let’s end this article with a couple of pros and cons of using type hints.
- They help to document your code – not a replacement for docstrings though
- They help in maintaining a cleaner codebase – for obvious reasons
- They improve the linting capabilities of your code editor – for example, PyCharm will show a warning if a type mismatch is detected
- Can be tedious to add – especially if you are not accustomed to them
To conclude – type hints are not required but are good practice, especially when working on large codebases – even if you decide not to use
What are your thoughts on type hints? Do you always use them, or just when the codebase gets larger? Let me know in the comment section below.