In Python, the arrow symbol (->
) appears in function definitions as a notation to indicate the expected return type. This notation is optional, but when you include it, you clarify what data type a function should return:
>>> def get_number_of_titles(titles: list[str]) -> int:
... return len(titles)
...
You may have observed that not all Python code includes this particular syntax. What does the arrow notation mean? In this tutorial, you’ll learn what it is, how to use it, and why its usage sometimes seems so inconsistent.
Get Your Code: Click here to download the free sample code that you’ll use to learn what -> means in Python function definitions.
Take the Quiz: Test your knowledge with our interactive “What Does -> Mean in Python Function Definitions?” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
What Does -> Mean in Python Function Definitions?Test your understanding of Python return type hints and learn how to use the -> arrow, annotate containers, and check code with static tools.
In Short: The ->
Notation Indicates a Function’s Return Type in Python
In Python, every value stored in a variable has a type. Because Python is dynamically typed, variables themselves don’t have fixed types—they can hold values of any type at different times. This means the same variable might store an integer at one moment and a string the next. In contrast, statically typed languages like C++ or Java require explicit type declarations, and variables are bound to a specific type throughout their lifetime.
You can see an example of a dynamically typed Python variable in the following code example:
>>> my_number = 32
>>> my_number = "32"
You start by declaring a variable called my_number
, and setting it to the integer value 32
. You then change the variable’s value to the string value "32"
. When you run this code in a Python environment, you don’t encounter any problems with the value change.
Dynamic typing also means you might not always know what data type a Python function will return, if it returns anything at all. Still, it’s often useful to know the return type. To address this, Python 3.5 introduced optional type hints, which allow developers to specify return types. To add a type hint, you place a ->
after a function’s parameter list and write the expected return type before the colon.
You can also add type hints to function parameters. To do this, place a colon after the parameter’s name, followed by the expected type—for example, int
or str
.
Basic Type Hint Examples
To further explore type hints, suppose that you’re creating a Python application to manage inventory for a video game store. The program stores a list of game titles, tracks how many copies are in stock, and suggests new games for customers to try.
You’ve already seen the type hint syntax in the code example introduced earlier, which returns the number of titles in a list of games that the game store carries:
>>> def get_number_of_titles(titles: list[str]) -> int:
... return len(titles)
...
>>> games = ["Dragon Quest", "Final Fantasy", "Age of Empires"]
>>> print("Number of titles:", get_number_of_titles(games))
Number of titles: 3
Here you see a type hint. You define a function called get_number_of_titles()
, which takes a list of game titles as input. Next, you add a type hint for the titles
parameter, indicating that the function takes a list of strings. Finally, you also add another type hint for the return type, specifying that the function returns an int
value.
The function returns the length of the list, which is an integer. You test this out in the next line, where you create a variable that stores a list of three game titles. When you invoke the function on the list, you verify that the output is 3
.
Note that in a real-world application, creating a separate function just to return a list’s length might be redundant. However, for instructional purposes, the function shown in the example is a straightforward way to demonstrate the type hint concept.
You can use type hints with any Python type. You’ve already seen an example with an int
return type, but consider another example with a str
return type. Suppose you want to recommend a random game for a customer to try. You could do so with the following short example function:
>>> import random
>>> def get_game_recommendation(titles: list[str]) -> str:
... return random.choice(titles)
...
>>> print("Random recommendation:", get_game_recommendation(games))
Random recommendation: Final Fantasy
You define a function called get_game_recommendation()
, which again takes a list as a parameter. This time, the return type hint suggests that the function returns a string. You then call the function, using the game list you created earlier, with a message to the user suggesting a random game.
You can also annotate functions that don’t return anything. Consider the following example, which searches for and prints out game titles that contain a given keyword:
>>> def find_keyword_in_titles(titles: list[str], keyword: str) -> None:
... print("Titles that contain the keyword:", keyword)
... for game_title in titles:
... if keyword in game_title:
... print(game_title)
...
>>> find_keyword_in_titles(games, "es")
Titles that contain the keyword: es
Dragon Quest
Age of Empires
You create a function find_keyword_in_titles()
that takes a list of game titles and a keyword as parameters. Next, you add a type hint indicating the return type as None
, meaning it doesn’t return anything. Instead, it loops through all titles in the list, printing out any title containing the keyword.
After you complete the function, you can test it with your game list, passing in "Final"
as the keyword. The function will print out "Final Fantasy"
.
Key Terms in Python Typing
As you explore this topic further, you’ll come across several different terms such as type annotations, type hints, and type checking, which are sometimes used interchangeably. Here are the definitions of these terms to help you keep them straight in your mind as you go through this tutorial:
- Type annotations: Annotations are an optional way to provide additional metadata about Python values. Type annotations, specifically, describe the types of values used in a program.
- Type hints: According to the Python documentation, a type hint is: “An annotation that specifies the expected type for a variable, a class attribute, or a function parameter or return value.” Type hints are also optional.
- Type checking: The process of verifying that variables and expressions match their specified types and follow the language’s rules.
Type annotations have been addressed in many Python Enhancement Proposals (PEPs). To help you understand the background and context of Python type hints, here’s a brief look at some of the most relevant PEPs:
Python 2 lacked standard function annotations, so developers created various external tools in an attempt to address the gap. In December 2006, PEP 3107 – Function Annotations introduced the concept of function annotations, a standardized syntax for adding arbitrary metadata about Python functions. It didn’t establish standard semantics for annotations, leaving that up to third-party tools and libraries.
In 2014, PEP 484 – Type Hints introduced the syntax for type hints, which rely on the annotations outlined in PEP 3107. PEP 484 assumes that external type-checker tools will use these hints, rather than Python itself enforcing consistency with them.
Around two years later, PEP 526 – Syntax for Variable Annotations was built on PEP 484 by adding syntax for variable annotations. Previously, developers indicated variable types through comments in the code rather than with any specialized syntax. Again, these annotations are optional, and any inconsistencies will not cause runtime errors in Python.
Now that you have an understanding of key terms and the history of type annotations and type hints in Python, it’s time to get a bit more practical again.
What Happens When a Function Returns a Different Type Than Annotated?
As you learned earlier, type hints are optional. The Python interpreter won’t actually enforce them. So if your function returns a value that doesn’t match the type hint, you won’t run into any errors or warnings in standard Python.
Consider the following code, where you revisit your function that returns the number of game titles in a list:
>>> def get_number_of_titles(titles: list[str]) -> str:
... return len(titles)
...
>>> games = ["Dragon Quest", "Final Fantasy", "Age of Empires"]
>>> print("Number of titles:", get_number_of_titles(games))
Number of titles: 3
The function is mostly the same as when you first saw it, but this time, the type hint indicates that the function should return a string value. This is intentionally incorrect, to show that Python itself won’t complain but a type checker will. Note that the function still returns an integer value. When you create a list and call the function, you can see that it happily returns and prints the integer, with no complaints from Python.
However, to add an extra level of type verification, you can use type hints in conjunction with certain tools, like linters and type checkers, to ensure that the return value matches the type hint. A linter is an automated software tool that analyzes code for problems with formatting and correctness, flagging possible issues. A type checker is a tool that checks code to ensure that all data values and variables are of the intended type.
Mypy is a popular Python type checker tool. You can use it to verify that your function parameters and return values match the declared type hints. It’s a tool that you can download and install as part of your development workflow. You can also try out a mypy playground online and experiment with type checking your own code.
If you use mypy to test your original get_number_of_titles()
function with the type hint indicating an int
return value, then you’ll see a success message:
"Success: no issues found in 1 source file"
However, if you try the version of the function with a str
value type hint, you’ll get an error message similar to the following:
main.py:2: error: Incompatible return value type (got "int", expected "str")
The function’s return type hint indicated that the function would return a string value. However, the function actually returned an integer value, so the mypy check flagged the incompatible return value.
What Types Can You Use After Python’s ->
?
Type hints aren’t limited to basic data types or Python built-in types. You can also use them with collections such as lists and dictionaries. In the next example, you’ll see how to annotate both the keys and values of a dictionary. The function processes a game inventory and returns only the titles with the highest stock:
>>> game_stock = {
... "Dragon Quest": 5,
... "Final Fantasy": 1,
... "Age of Empires": 5
... }
>>> def get_highest_stock_games(game_stock: dict[str, int]) -> dict[str, int]:
... max_quantity = max(game_stock.values())
... return {
... game: quantity
... for game, quantity in game_stock.items()
... if quantity == max_quantity
... }
...
>>> print("Games with the highest stock:", get_highest_stock_games(game_stock))
Games with the highest stock: {'Dragon Quest': 5, 'Age of Empires': 5}
You start by defining a dictionary called game_stock
that pairs game titles with the number of available copies. Then, you create a function get_highest_stock_games()
, which takes the game stock dictionary as a parameter and returns a dictionary of string and integer pairs. Each pair in this dictionary represents a game title and its number of copies, and it contains the titles with the highest number of copies available.
Note that in this example, when you add a type hint for a complex data structure, you not only specify the structure’s data type but also the types it contains. You won’t get errors if you leave out the element types, though. For example, a type hint of simply -> dict:
will also work, but using dict[str, int]
is considered best practice because it provides more specific type information.
The function efficiently finds the maximum quantity using the max()
function, then uses a dictionary comprehension to return all games with that maximum quantity. As the return type hint specifies, the dictionary consists of string and integer pairs.
Finally, you return the resulting dictionary and print it to the screen. When you run the code, you see from the output that the returned dictionary matches the type hint.
If you create your own classes, then you can use them as return types as well. You can also use type hints to specify multiple possible return types from one function. For example, if you were to create a class to represent games as objects, then you might have a function that can return a game object if the game is in stock, or None
otherwise.
Where Can You Use ->
Beyond Functions?
In addition to functions, you can also use the arrow notation for methods in classes. For example, suppose you end up creating a Game
class to represent game objects:
class Game:
def __init__(self, name: str, genre: str, price: float) -> None:
self.name = name
self.genre = genre
self.price = price
def get_name(self) -> str:
return self.name
def get_genre(self) -> str:
return self.genre
def get_price(self) -> float:
return self.price
You define a very basic Game
class, with a constructor and a few class attributes: a name, a genre, and a price. The class constructor has a type hint indicating that it returns None
, while the getter methods for the attributes have type hints indicating that they return a string for the name, a string for the genre, and a float
for the price.
What Are the Benefits of Using Return Type Hints?
Type hints help your code to be more self-documenting. Rather than writing comments, you can use the ->
syntax to make it more convenient for readers to understand what sort of output to expect from a function, just by looking at the function signatures.
Used alongside tools like linters and type checkers, type hints can help you catch errors before they cause problems in your code. By ensuring that your functions return the proper type, you avoid situations where you try to perform invalid operations on the wrong kind of data. For example, if you’re expecting to perform a mathematical calculation on a certain returned value, you don’t want the function to return a string instead of a number.
Using type checkers and other automated tools with the ->
syntax to verify your return values can save you development time. These tools identify problems that you would otherwise need to spend valuable time tracing and debugging yourself.
Are There Any Drawbacks to Using Return Type Hints?
As with any documentation, developers must keep return type hints up to date as the code changes. You might need to update them for several reasons, including the following:
- Updates to the project requirements: A program may need to handle a different type of data than originally stipulated. For example, imagine that you needed to change your
get_highest_stock_games()
function to returnGame
objects and integer pairs, rather than strings and integers. - Code refactoring: Changes in how functions interact may require updates to return types and their annotations. For instance, suppose that in the
find_keyword_in_titles()
function you wanted to use the matching titles elsewhere in the program, instead of just printing them out. You’d need to change the return type fromNone
tostr
or some other type. - Corrections or bug fixes: Sometimes you just make mistakes in your code, such as using the wrong return type. In the
Game
class, you saw that theget_price()
method returns afloat
value. If you’d mistakenly made theprice
attribute and theget_price()
return type hint an integer, you’d need to correct that logical error.
The standard Python interpreter doesn’t enforce type hints, so you may feel a false sense of security if you’re unaware of this limitation. If you expect to use a linter, type checker, or other verification tool, then you may still have to do manual type verification if, for some reason, the project doesn’t use these tools.
In such cases, the ->
syntax might not be as helpful in practice, besides reminding you of what the proper output should be. That said, most modern code editors provide built-in support for type hints, making them easier to use effectively.
Conclusion
You’ve learned about the ->
notation in Python and discovered what it means and how to use it. By considering a theoretical video game inventory application, you saw how type hints can apply to both functions and class methods.
You also gained valuable insight into the history and reasoning behind type hints, giving you a better context for the challenges that they address for developers.
In this tutorial, you’ve learned how to:
- Use the
->
notation in function definitions to specify a function’s return type - Add type hints to parameters, return values, containers, and class methods
- Check your type hints with tools like mypy to catch errors early
- Weigh the benefits and drawbacks of return type hints for readability, maintainability, and compatibility
Now that you know about type hints and the ->
syntax, you’ve gained a valuable skill that can help you make your code more readable and self-documenting. When you use them consistently, you’ll make development smoother for yourself and your colleagues while maintaining higher-quality code.
Get Your Code: Click here to download the free sample code that you’ll use to learn what -> means in Python function definitions.
Frequently Asked Questions
Now that you have some experience with the arrow symbol (->
) and return type hints in Python, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click the Show/Hide toggle beside each question to reveal the answer.
When you see ->
in a Python function definition, it specifies the expected return type of that function as a type hint.
You use the arrow symbol (->
) in a function or method signature to indicate the type of value you expect the function to return.
When you write -> str
after a function’s parameters, you signal that the function is expected to return a string value.
You can use any valid Python type after ->
, including basic types like int
, str
, and float
, as well as complex types like list
, dict
, custom classes, or even None
if the function returns nothing.
Return type hints allow you to specify what type a function should return, which improves the readability of your code and assists tools like linters and type checkers in identifying potential errors before you run your program.
Take the Quiz: Test your knowledge with our interactive “What Does -> Mean in Python Function Definitions?” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
What Does -> Mean in Python Function Definitions?Test your understanding of Python return type hints and learn how to use the -> arrow, annotate containers, and check code with static tools.