What are Python type hints?
Type hints in Python specify the type of variables or functions parameters as well as the return type. You can read more about them in the PEP 484 Guidelines.
In general they work like type declarations in every typed programming language, like Java or C++. The only difference is that type hints are completely optional. Python remains a dynamic language, because the Interpreter simply ignores the type hints. They are only relevant for development and have no influence on the execution. Accordingly, you can run a Python program with completely incorrect type hints without getting any errors.
Type hints exist just for you as a developer to make your life easier - so you should use them!
Types in Python
Python has many built-in types, way more than you might have expected. Some common examples for build-in types are str for strings, int for integers and bool for boolean values.
Furthermore, types are objects like everything else in Python. By the way, you can actually use types as keys for a dictionary. So the following code really works!
types_mapping = {int: "Integer",str: "String",bool: "Boolean",}print(types_mapping[int])
Okay, you can do lots of things with the build-in types, but they are not really specific. For instance, you can have a variable of the type list, but what's actually in the list? Nobody knows.
That's why Python 3.5 introduced the typing module! You can import various types from this module, which you can specify really precisely. The following examples show some features of the typing module, but feel free to take some time and explore the module on your own.
How do type hints look like?
The syntax for type hints is, like the Python syntax in general, very simple.
In the following code example, you can see some type specifications for variables. The according syntax is just a colon after the variable name followed by the type.
# Type Hints with build-in typesage: int = 42names: list = ["Alice", "Bob"]translations: dict = {1: "one", 2: "two"}are_type_hints_great: bool = True# Type Hints with the typing modulefrom typing import List, Tuple, Callablenames: List[str] = ["Alice", "Bob"]translations: dict = {1: "one", 2: "two"}fruits: Tuple[str] = ("apple", "banana", "kiwi")my_lambda: Callable = lambda name: f"Hello {name}"# Type Hints using self defined classesclass Dog:passalice: Dog = Dog()
For these examples the types might seem a bit redundant and obvious. In fact, you will use this kind of Type Hint rather seldom in comparison to the others. But when you use the returned object of a function for instance, you may not know the type of it.
More frequently used are type hints for parameters, and they basically work just the same as for variables. But note that this applies for parameters with default arguments too!
from typing import List, Tuple, Dictclass Car:passdef too_many_parameters(name: str, amount: float = 6.66, the_number: int = 42):passdef more_parameters(scores: List[int], persons: Dict[str, Tuple[str, int]]):passdef and_even_more_parameters(police_car: Car, racing_cars=List[Car]):pass
Another possibility to specify type hints is for the return type of a function. There is also another syntax for this case: You specify the return type with an "arrow", followed by the type. It is important that the type is in the function definition before the colon.
from typing import List, Tupleclass House:passdef calculate_average(numbers: List[int]) -> float:passdef get_all_customer_names() -> List[str]:passdef get_my_house() -> House:passdef get_my_neighbours() -> Tuple[House]:pass
This is the complete syntax you need to know if you want to use type hints! Easy, isn't it?
Benefits of specifying types
Some IDEs like PyCharm support type hints in different ways. First of all, PyCharm complains when a type hint does not matches with your coding. Additionally, you get a suggestion what the type should be or what is expected. This prevents unintentional behaviours where you expect a type and are surprised when you get something completely different. With type hints, you don't have to reengineer every function you want to call just for knowing what it will return anymore. In most cases, the combination of the function name and the type specifications make it clear how to use the function. If it doesn't, you should improve the readability of your code, for example by applying the KISS Principle or giving Meaningful Names.
Another really useful feature is the auto-completion! A common use-case for this scenario is an instance object from a class with some attributes and methods.
class Dog:def __init__(self, name):self.name = namedef bark(self):print(f"{self.name} barks!")def get_dog_from_name(dog_name):return Dog(dog_name)alice = get_dog_from_name("Alice")alice.bark()
If you call a function which returns an object, you might store it in a variable and work with it. Without type hints, the IDE wouldn't know what alice is. If you type a point after the name, you won't get any useful suggestions for functions or attributes of the Dog class. This changes when you add type hints!
class Dog:def __init__(self, name: str):self.name = namedef bark(self):print(f"{self.name} barks!")def get_dog_from_name(dog_name: str) -> Dog:return Dog(dog_name)alice = get_dog_from_name("Alice")alice.bark()
Now you will get all possible suggestions for working with the class instance.
As we have seen, type hints are a really powerful tool to increase your productivity and motivation. It also greatly improves the readability of your code as everyone can quickly see what kind of objects you are working with. So all in all, you should definitely use type hints!