Any
from typing import Any
def get_first(items: list) -> Any:
return items[0]
Warning: beginners often get lazy with their type annotations, and tend to write Any even when a more specific type annotation is appropriate. While this will cause code analysis tools (like PyCharm or python_ta) to be satisfied and not report errors, overuse of Any completely defeats the purpose of type annotations! Remember that we use type annotations as a form of communication, to tell other programmers how to use our function or class. With this goal in mind, we should always prefer giving specific type annotations to convey the most information possible, and only use Any when absolutely necessary.
Union
We sometimes want to express in a type annotation that a value could be one of two different types; for example, we might say that a function can take in either an integer or a float. To do so, we use the Union type. For example, the type Union[int, float] represents the type of a value that could be either an int or a float.
from typing import Union
def cube_root(x: Union[int, float]) -> float:
return x ** (1/3)
Optional
One of the most common uses of a “union type” is to say that a value could be a certain type, or None. For example, we might say that a function returns an integer or None, depending on some success or failure condition. Rather than write Union[int, None], there’s a slightly shorter version from the typing module called Optional. The type expression Optional[T] is equivalent to Union[T, None] for all type expressions T. Here is an example:
from typing import Optional
def find_pos(numbers: List[int]) -> Optional[int]:
“”“Return the first positive number in the given list.
Return None if no numbers are positive.
“””
for n in numbers:
if n > 0:
return n
Callable
Finally, we sometimes need to express that the type of a parameter, return value, or instance attribute is itself a function. To do so, we use the Callable type from the typing module. This type takes two expressions in square brackets: the first is a list of types, representing the types of the function’s arguments; the second is its return type. For example, the type Callable[[int, str], bool] is a type expression for a function that takes two arguments, an integer and a string, and returns a boolean. Below, the type annotation for compare_nums declares that it can take any such function:
from typing import Callable
def compare_nums(num1: int, num2: int,
comp: Callable[[int, int], bool]) -> int:
if comp(num1, num2):
return num1
else:
return num2
def is_twice_as_big(num1: int, num2: int) -> bool:
return num1 >= 2 * num2
compare_nums(10, 3, is_twice_as_big)
10
compare_nums(10, 6, is_twice_as_big)
6