Using Type Hints When Defining A Python Function [Intermediate Python Functions Series #6]

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:

  1. Introduction to the series: Do you know all your functions terminology well?
  2. Choosing whether to use positional or keyword arguments when calling a function
  3. Using optional arguments by including default values when defining a function
  4. Using any number of optional positional and keyword arguments: args and kwargs
  5. Using positional-only arguments and keyword-only arguments: the “rogue” forward slash / or asterisk * in function signatures
  6. [This article] Type hinting in functions
  7. 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.

Screenshot from PyCharm showing warnings due to type hints in Python

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:

Screenshot from PyCharm showing warnings due to type hints in Python for function return values

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: Best Practices When Defining And Using Python Functions

Further Reading


Get the latest blog updates

No spam promise. You’ll get an email when a new blog post is published


4 thoughts on “Using Type Hints When Defining A Python Function [Intermediate Python Functions Series #6]”

Leave a Reply