Sling Academy
Home/Python/Python: Typing a function that can return multiple types

Python: Typing a function that can return multiple types

Last updated: February 17, 2024

Introduction

Python, as a dynamically typed language, offers significant flexibility regarding variable types. A function in Python can return different types of data, making it versatile but challenging for type checking and code clarity. Fortunately, the typing module in Python 3.5 and later versions provides tools to declare the types of variables, function arguments, and return values, even for functions with multiple return types.

This tutorial covers how to use Python’s typing module to specify types for functions that can return multiple types. We’ll discuss different strategies such as using Union, Any, Optional, and the newer Literal and TypedDict for Python 3.8 and later, including practical examples to illustrate their use.

Understanding Static Typing in Python

Before diving into the specifics of typing a function with multiple return types, it’s essential to understand the concept of static typing in Python. Static typing involves explicitly specifying the type of a variable at compile time, allowing for type checking before runtime. This is opposed to Python’s default dynamic typing, where types are inferred at runtime. Python’s typing module allows for a hybrid approach, adding static type hints without sacrificing Python’s dynamic nature.

Using Union for Multiple Return Types

The Union type hint from the typing module lets you specify that a function may return more than one type. Consider the following example:

from typing import Union
def get_data(flag: bool) -> Union[int, str]:
    if flag:
        return 34
    else:
        return "Not an integer"

This function returns either an integer or a string, based on the flag parameter.

Using Any When Any Type is Possible

When a function can return elements of any type, the Any type hint indicates a return value of any type. Here’s how you might use Any:

from typing import Any
def get_anything(flag: int) -> Any:
    if flag == 1:
        return 42
    elif flag == 2:
        return "The answer"
    else:
        return None

The Role of Optional in Typing

The Optional type hint implies that a function may return a certain type or None. It is a shorthand for Union[T, None], useful for functions that may not return a value:

from typing import Optional
def maybe_return(flag: bool) -> Optional[int]:
    if flag:
        return 123
    else:
        return None

Exploring Newer Typing Options

Python 3.8 introduced Literal and TypedDict, offering more granularity in specifying function return types. Literal allows specifying literal values a function can return, while TypedDict enables detailing the types of keys and values a dictionary function may return. See the examples below for how to use these in your code:

from typing import Literal, TypedDict
class NumbersDict(TypedDict):
    number: int
    description: str
def get_specific_value(flag: int) -> Literal['yes', 'no', 'maybe']:
    if flag == 1:
        return 'yes'
    elif flag == 2:
        return 'no'
    else:
        return 'maybe'

def get_number_info() -> NumbersDict:
    return {'number': 42, 'description': 'The ultimate answer'}

Best Practices for Typing

While the typing module offers great flexibility, it’s crucial to use type hints appropriately to maintain code readability and avoid confusion. Here are some best practices to follow:

  • Use specific type hints whenever possible to enhance code clarity and facilitate type checking.
  • Leverage Union, Optional, and Any strategically, avoiding overuse that can lead to ambiguity.
  • Stay updated with the latest Python versions for more advanced typing features that can further improve your code.

Conclusion

This tutorial introduced you to typing functions with multiple return types in Python, using the typing module. Through examples featuring Union, Any, Optional, Literal, and TypedDict, we demonstrated how to add static type hints to your Python code. By embracing these techniques, you can improve your code’s readability, robustness, and ease of maintenance.

Next Article: Python: Typing a function with *args and **kwargs

Previous Article: Type Casting in Python: The Ultimate Guide (with Examples)

Series: Basic Python Tutorials

Python

You May Also Like

  • Introduction to yfinance: Fetching Historical Stock Data in Python
  • Monitoring Volatility and Daily Averages Using cryptocompare
  • Advanced DOM Interactions: XPath and CSS Selectors in Playwright (Python)
  • Automating Strategy Updates and Version Control in freqtrade
  • Setting Up a freqtrade Dashboard for Real-Time Monitoring
  • Deploying freqtrade on a Cloud Server or Docker Environment
  • Optimizing Strategy Parameters with freqtrade’s Hyperopt
  • Risk Management: Setting Stop Loss, Trailing Stops, and ROI in freqtrade
  • Integrating freqtrade with TA-Lib and pandas-ta Indicators
  • Handling Multiple Pairs and Portfolios with freqtrade
  • Using freqtrade’s Backtesting and Hyperopt Modules
  • Developing Custom Trading Strategies for freqtrade
  • Debugging Common freqtrade Errors: Exchange Connectivity and More
  • Configuring freqtrade Bot Settings and Strategy Parameters
  • Installing freqtrade for Automated Crypto Trading in Python
  • Scaling cryptofeed for High-Frequency Trading Environments
  • Building a Real-Time Market Dashboard Using cryptofeed in Python
  • Customizing cryptofeed Callbacks for Advanced Market Insights
  • Integrating cryptofeed into Automated Trading Bots