When using Python type hints, you encounter cases where “this variable might contain an integer or a string” or “the data type cannot be specified.” To handle such flexible type definitions, Python provides the Union type (or | operator) and the Any type.
This article explains how to use these two and their appropriate use cases.
1. Allowing Multiple Types (Union / |)
Use this when a variable can take one of multiple types, such as “A or B”.
Notation for Python 3.10 and later (| Operator)
From Python 3.10, you can use the pipe symbol | to intuitively express “or”. This notation is currently recommended.
Syntax: TypeA | TypeB
Example: Define a function that accepts both an integer (e.g., 101) and a string (e.g., “user_01”) as a User ID.
def get_user_name(user_id: int | str) -> str:
"""
Function to accept User ID (int or str) and return name.
"""
if isinstance(user_id, int):
return f"User(No.{user_id})"
else:
return f"User(ID:{user_id})"
# --- Execution ---
print(get_user_name(500)) # Pass int
print(get_user_name("admin")) # Pass str
Output:
User(No.500)
User(ID:admin)
Notation for Python 3.9 and earlier (Union)
If you are using an older version of Python, import Union from the standard library typing module. The meaning is exactly the same as |.
Syntax: Union[TypeA, TypeB]
from typing import Union
# Variable that might contain int, float, or None
# Equivalent to int | float | None in Python 3.10+
measurement_value: Union[int, float, None] = 12.5
print(f"Measured Value: {measurement_value}")
2. Accepting Any Type (Any)
If you want to explicitly state that “any type is acceptable,” use Any from the typing module. Specifying Any effectively disables type checking for that variable. It is used when dealing with dynamic data or during transitional periods where specifying types is difficult.
Syntax: Any
Example: Define a generic function that accepts any data and logs its type and content.
from typing import Any
def log_debug_info(data: Any) -> None:
"""
Accepts data of any type and outputs info.
"""
print(f"[Debug] Type: {type(data)} | Value: {data}")
# --- Execution ---
log_debug_info(1024) # int
log_debug_info("System Error") # str
log_debug_info([1, 2, 3]) # list
log_debug_info({"key": "value"}) # dict
Output:
[Debug] Type: <class 'int'> | Value: 1024
[Debug] Type: <class 'str'> | Value: System Error
[Debug] Type: <class 'list'> | Value: [1, 2, 3]
[Debug] Type: <class 'dict'> | Value: {'key': 'value'}
Note on Using Any
While Any is convenient, overusing it defeats the purpose of “error detection via type hints.” It is recommended to narrow down types like int | str as much as possible, and use Any only when the type is truly unidentifiable or unknown due to library specifications.
Summary
int | str: Use when there are multiple candidates like “integer or string” (Python 3.10+).Union[int, str]: Notation for older versions with the same meaning as above.Any: Use when “any type is fine.” Since it disables type checking, keep its use to a minimum.
