You’ve already covered a lot of ground in this Intermediate Python Functions series. In this article, you’ll read about a relatively new addition in Python called type hinting or type annotation. Unlike all the other topics you learnt about in the previous articles, this one will not change the behaviour of the function you define. So why bother? Let’s find out.
Overview Of The Intermediate Python Functions Series
Here’s an overview of the seven articles in this series:
- Introduction to the series: Do you know all your functions terminology well?
- Choosing whether to use positional or keyword arguments when calling a function
- Using optional arguments by including default values when defining a function
- Using any number of optional positional and keyword arguments:
args
andkwargs
- Using positional-only arguments and keyword-only arguments: the “rogue” forward slash / or asterisk * in function signatures
- [This article] Type hinting in functions
- Best practices when defining and using functions
Type Hints in Python Functions
Let’s see what type hints are with the following example:
def greet_person(person: str, number: int): for greeting in range(number): print(f"Hello {person}! How are you doing today?") # 1. greet_person("Sam", 4) # 2. greet_person(2, 4)
You define the function greet_person()
which has two parameters:
person
number
In the function definition, the parameters also have type hints. The type hint follows immediately after the parameter name and a colon. The function’s signature shows str
as the data type annotation for person
and int
as the annotation for number
.
However, these are just hints or annotations. They do not force the parameters to take only those data types as inputs. You can confirm this by running the code above. Both function calls run without errors even though the second call has an int
as its first argument when its type hint indicates that it’s meant to be a str
:
Hello Sam! How are you doing today? Hello Sam! How are you doing today? Hello Sam! How are you doing today? Hello Sam! How are you doing today? Hello 2! How are you doing today? Hello 2! How are you doing today? Hello 2! How are you doing today? Hello 2! How are you doing today?
So, if the code still works, what do type hints do?
Tools Which Make Use Of Type Hints in Python Functions
Let’s look at the code above as seen in the IDE I’m using. I’m using PyCharm, but you’ll also get similar behaviour in other IDEs.
You can see that one of the arguments is highlighted in yellow in the second function call. The first argument, the integer 2
, has a warning. When you hover over the argument, a warning pops up: “Expected type ‘str’, got ‘int’ instead”.
Even though the code still runs and doesn’t give an error message, the IDE warns you before you run your code to inform you that the argument you used doesn’t match the expected date type. The expected data type is the one used in the type hint.
There are other tools which check type hints and provide warnings, too. Therefore, even though type hints do not change the function’s behaviour, they can minimise errors and bugs. The user is less likely to misuse the function if they get warnings when using the wrong data types.
Type Hints For Return Values in Python Functions
Let’s look at another variation of the function:
def greet_people(people: list) -> list: return [f"Hello {person}! How are you doing today?" for person in people] result = greet_people(["James", "Matthew", "Claire"]) for item in result: print(item.upper())
The parameter people
has a type annotation showing it should be passed a list. There’s also the ->
symbol followed by list
before the colon at the end of the function signature. You’ll see what this is soon.
Let’s first look at the output from this code:
HELLO JAMES! HOW ARE YOU DOING TODAY? HELLO MATTHEW! HOW ARE YOU DOING TODAY? HELLO CLAIRE! HOW ARE YOU DOING TODAY?
The annotation -> list
at the end of the signature shows that the function’s return value should be a list. This type hint lets anyone reading the function definition know that this function returns a list.
More complex type hints
Let’s go a bit further to see the benefit of this type of annotation. Here’s another version. There’s an error in the for
loop:
def greet_people(people: list) -> list: return [f"Hello {person}! How are you doing today?" for person in people] result = greet_people(["James", "Matthew", "Claire"]) for item in result: print(item.append(5))
This code raises the following error:
Traceback (most recent call last): File "...", line 7, in <module> print(item.append(5)) ^^^^^^^^^^^ AttributeError: 'str' object has no attribute 'append'
The variable result
is a list which contains strings. Therefore, the variable item
in the for
loop will contain a string. You cannot use append()
on these strings since append()
is not a str
method. The type annotation you have now doesn’t help in this situation. It indicates that the function should return a list, which it does.
But is it possible to get a warning of this issue before you run the code using type hints? Can we find out that this is not the right kind of list?
Let’s improve the return value’s type annotation:
def greet_people(people: list) -> list[str]: return [f"Hello {person}! How are you doing today?" for person in people] result = greet_people(["James", "Matthew", "Claire"]) for item in result: print(item.append(5))
Note that the return value’s type annotation is now list[str]
. This indicates that the function returns a list of strings, not just any list.
Let’s see what this code looks like in PyCharm:
The IDE highlights the append()
method on the last line. Type hints indicate that the data the function returns is a list of strings. Therefore the IDE “knows” that item
should be a str
in the final for
loop since result
is a list of strings. The IDE warns you that append()
is not a string method.
Should You Start Using Type Hints When Defining Python Functions?
Opinions are split in the Python community on how and when you should use type hinting. Python is a dynamic language–this means that you don’t have to declare the data type of variables as they are dynamically assigned when the program runs. Type hinting does not make Python a static language.
You may hear some say that you should always use type hints. In some programming environments, such as in teams writing production code, type hints have nearly become standard. They make working in large teams easier and minimise bugs. In such programming teams, type hints are almost always used.
However, there are situations when you don’t need them and the code you write is simpler without them. There are still many programming applications in which code which doesn’t have type hints is perfectly fine.
So don’t feel pressured to use them all the time!
Next Article:<Link will be posted here when the next article in the series is posted>
Further Reading
- Chapter 3: Power-up Your Coding: Create Your Own Functions for an in-depth introduction to Python functions
- Chapter 6: Functions Revisited. This chapter covers topics that will be dealt with later on in the series
- The White Room: Understanding Programming. In this article, I briefly referred to parameters as boxes which store data. This is part of a broader analogy I like to use. You can read more in this chapter
- Using Python Optional Arguments When Defining Functions is an article I wrote for Real Python if you want to read ahead.
Get the latest blog updates
No spam promise. You’ll get an email when a new blog post is published
The post Using type hints when defining a Python function [Intermediate Python Functions Series #6] appeared first on The Python Coding Book.