= Python Typing = '''`typing`''' and '''`typing_extensions`''' modules support the [[Python/TypeAnnotation|type annotation system]]. `typing_extensions` is the experimental namespace; `typing` is the mature namespace. Any classes or functions that have migrated from the former to the latter will be documented ''only'' as being a member of `typing`. The type annotation system has evolved rapidly with many breaking changes. Anything that has been moved out of `typing` (and `typing_extensions`) will be documented ''elsewhere'', with a note about the migration. <> ---- == Primitives and Collections == === AbstractSet === Do not use `typing.AbstractSet[...]` in Python 3.9+; instead use `collections.abc.Set[...]`. See [[Python/Collections/Abc#Set|here]] for more details. === Any === `Any` satisfies all type checking, which can be useful for making things 'just work'. === AnyStr === If a function can take either a normal string or a byte string (`b""`), annotate the argument with `AnyStr`. This will satisfy type checkers while still catching issues relating to the combination of these incompatible types {{{ def concat(a: AnyStr, b: AnyStr) -> AnyStr: return a + b # pass concat("foo", "bar") # pass concat(b"foo", b"bar") # fail concat("foo", b"bar") }}} === AsyncContextManager === Do not use `typing.AsyncContextManager[...]` in Python 3.9+; instead use `contextlib.AbstractAsyncContextManager[...]`. See [[Python/ContextLib#AbstractAsyncContextManager|here]] for more details. === AsyncGenerator === Do not use `typing.AsyncGenerator[...]` in Python 3.9+; instead use `collections.abc.AsyncGenerator[...]`. See [[Python/Collections/Abc#AsyncGenerator|here]] for more details. === AsyncIterable === Do not use `typing.AsyncIterable[...]` in Python 3.9+; instead use `collections.abc.AsyncIterable[...]`. See [[Python/Collections/Abc#AsyncIterable|here]] for more details. === AsyncIterator === Do not use `typing.AsyncIterator[...]` in Python 3.9+; instead use `collections.abc.AsyncIterator[...]`. See [[Python/Collections/Abc#AsyncIterator|here]] for more details. === Awaitable === Do not use `typing.Awaitable[...]` in Python 3.9+; instead use `collections.abc.Awaitable[...]`. See [[Python/Collections/Abc#Awaitable|here]] for more details. === BinaryIO === A subclass of `typing.IO` specific to byte streams plus type annotations for a few byte stream specific methods. Leaving the second point aside, equivalent to `IO[bytes]`. === ByteString === Do not use `typing.ByteString[...]` in Python 3.9+; instead use `collections.abc.ByteString[...]`. See [[Python/Collections/Abc#ByteString|here]] for more details. === Callable === Do not use `typing.Callable[...]` in Python 3.9+; instead use `collections.abc.Callable[...]`. See [[Python/Collections/Abc#Callable|here]] for more details. === ChainMap === Do not use `typing.ChainMap[...]` in Python 3.9+; instead use `collections.chainmap[...]`. See [[Python/Collections#chainmap|here]] for more details. === Collection === Do not use `typing.Collection[...]` in Python 3.9+; instead use `collections.abc.Collection[...]`. See [[Python/Collections/Abc#Collection|here]] for more details. === Container === Do not use `typing.Container[...]` in Python 3.9+; instead use `collections.abc.Container[...]`. See [[Python/Collections/Abc#Container|here]] for more details. === ContextManager === Do not use `typing.ContextManager[...]` in Python 3.9+; instead use `contextlib.AbstractContextManager[...]`. See [[Python/ContextLib#AbstractContextManager|here]] for more details. === Coroutine === Do not use `typing.Coroutine[...]` in Python 3.9+; instead use `collections.abc.Coroutine[...]`. See [[Python/Collections/Abc#Coroutine|here]] for more details. === Counter === Do not use `typing.Counter[...]` in Python 3.9+; instead use `collections.Counter[...]`. See [[Python/Collections#Counter|here]] for more details. === DefaultDict === Do not use `typing.DefaultDict[...]` in Python 3.9+; instead use `collections.defaultdict[...]`. See [[Python/Collections#DefaultDict|here]] for more details. === Deque === Do not use `typing.Deque[...]` in Python 3.9+; instead use `collections.deque[...]`. See [[Python/Collections#Deque|here]] for more details. === Dict === Do not use `typing.Dict[...]` in Python 3.9+; instead use the built-in `dict[...]`. See [[Python/Builtins/Types#Dict|here]] for more details. === FrozenSet === Do not use `typing.FrozenSet[...]` in Python 3.9+; instead use the built-in `frozenset[...]`. See [[Python/Builtins/Types#FrozenSet|here]] for more details. === Generator === Do not use `typing.Generator[...]` in Python 3.9+; instead use `collections.abc.Generator[...]`. See [[Python/Collections/Abc#Generator|here]] for more details. === Hashable === An alias for `collections.abc.Hashable`. See [[Python/Collections/Abc#Hashable|here]] for more details. === ItemsView === Do not use `typing.ItemsView[...]` in Python 3.9+; instead use `collections.abc.ItemsView[...]`. See [[Python/Collections/Abc#ItemsView|here]] for more details. === Iterable === Do not use `typing.Iterable[...]` in Python 3.9+; instead use `collections.abc.Iterable[...]`. See [[Python/Collections/Abc#Iterable|here]] for more details. === Iterator === Do not use `typing.Iterator[...]` in Python 3.9+; instead use `collections.abc.Iterator[...]`. See [[Python/Collections/Abc#Iterator|here]] for more details. === IO === A byte or string stream, such as what is returned by `open()`. Can be type constrained to one or the other with `IO[bytes]` or `IO[str]`. === KeysView === Do not use `typing.KeysView[...]` in Python 3.9+; instead use `collections.abc.KeysView[...]`. See [[Python/Collections/Abc#KeysView|here]] for more details. === List === Do not use `typing.List[...]` in Python 3.9+; instead use the built-in `list[...]`. See [[Python/Builtins/Types#List|here]] for more details. === Literal === To annotate an argument or return value that must be one of a set of literal values, use `Literal`. {{{ from typing import Literal def true() -> Literal[True]: return True def open_helper(file: str, mode: Literal['r', 'rb', 'w', 'wb']) -> None: pass }}} === LiteralString === To annotate a string argument or return value that must one of... * a literal string value * a string value annotated as `Literal` or `LiteralString` * a combination of the above ...use `LiteralString`. As an example, consider SQL templating functions. {{{ from typing import LiteralString def run_query(sql: LiteralString) -> None pass def caller(arbitrary_string: str, literal_string: LiteralString) -> None: # pass, because is a literal string run_query("SELECT * FROM students") # pass, because is a value annotated as a LiteralString run_query(literal_string) # pass, because is a combination of a literal string and a value annotated as a LiteralString run_query("SELECT * FROM " + literal_string) run_query(arbitrary_string) # type checker error run_query( # type checker error f"SELECT * FROM students WHERE name = {arbitrary_string}" ) }}} This adds a degree of safety by way of the type checker. The following `str` methods all preserve `LiteralString` annotation. * `capitalize` * `casefold` * `center` * `expandtabs` * `format` * `join` * `ljust` * `lower` * `lstrip` * `partition` * `removeprefix` * `removesuffix` * `replace` * `rjust` * `rpartition` * `rsplit` * `rstrip` * `split` * `splitlines` * `strip` * `swapcase` * `title` * `upper` * `zfill` * `__add__` * `__iter__` * `__mod__` * `__mul__` * `__repr__` * `__rmul__` * `__str__` * [[Python/FStrings|f-strings]] === Mapping === Do not use `typing.Mapping[...]` in Python 3.9+; instead use `collections.abc.Mapping[...]`. See [[Python/Collections/Abc#Mapping|here]] for more details. === MappingView === Do not use `typing.MappingView[...]` in Python 3.9+; instead use `collections.abc.MappingView[...]`. See [[Python/Collections/Abc#MappingView|here]] for more details. === Match === Do not use `typing.Match[...]` in Python 3.9+; instead use `re.Match[...]`. See [[Python/Re#TypeAnnotations|here]] for more details. === MutableMapping === Do not use `typing.MutableMapping[...]` in Python 3.9+; instead use `collections.abc.MutableMapping[...]`. See [[Python/Collections/Abc#MutableMapping|here]] for more details. === MutableSequence === Do not use `typing.MutableSequence[...]` in Python 3.9+; instead use `collections.abc.MutableSequence[...]`. See [[Python/Collections/Abc#MutableSequence|here]] for more details. === MutableSet === Do not use `typing.MutableSet[...]` in Python 3.9+; instead use `collections.abc.MutableSet[...]`. See [[Python/Collections/Abc#MutableSet|here]] for more details. === NamedTuple === Named tuples are created like: {{{ from collection import namedtuple Employee = namedtuple('Employee', ['name', 'id']) }}} To create a named tuple with type annotations, the equivalent code is: {{{ from typing import NamedTuple class User(NamedTuple): name: str uid: int }}} It is also possible to insert methods and docstrings into named tuples created in this manner. To create a named tuple with [[Python/Typing#Generic_Types|generic types]], try: {{{ from typing import NamedTuple, Generic, TypeVar T = TypeVar('T') class User(NamedTuple, Generic[T]): own_group: T all_groups: list[T] }}} === Optional === To annotate an argument that can also be `None`, use `Optional`. {{{ from typing import Optional def int_or_none(arg: Optional[int]) -> None: if arg is not None: # type checkers understand type guards; `arg` is checked as an `int` here arg += 1 }}} === OrderedDict === Do not use `typing.OrderedDict[...]` in Python 3.9+; instead use `collections.ordereddict[...]`. See [[Python/Collections#OrderedDict|here]] for more details. === Pattern === Do not use `typing.Pattern[...]` in Python 3.9+; instead use `re.Pattern[...]`. See [[Python/Re#TypeAnnotations|here]] for more details. === Reversible === Do not use `typing.Reversible[...]` in Python 3.9+; instead use `collections.abc.Reversible[...]`. See [[Python/Collections/Abc#Reversible|here]] for more details. === Set === Do not use `typing.Set[...]` in Python 3.9+; instead use the built-in `set[...]`. See [[Python/Builtins/Types#Set|here]] for more details. === Sequence === Do not use `typing.Sequence[...]` in Python 3.9+; instead use `collections.abc.Sequence[...]`. See [[Python/Collections/Abc#Sequence|here]] for more details. === Sized === An alias for `collections.abc.Sized`. See [[Python/Collections/Abc#Sized|here]] for more details. === TextIO === A subclass of `typing.TextIO` specific to string streams plus type annotations for a few string stream specific methods. Leaving the second point aside, equivalent to `IO[str]`. The added method annotations include: * `buffer` * `encoding` * `errors` * `line_buffering` * `newlines` === Tuple === Do not use `typing.Tuple[...]` in Python 3.9+; instead use the built-in `tuple[...]`. See [[Python/Builtins/Types#Tuple|here]] for more details. === TypedDict === To create a dictionary with type annotations, try: {{{ from typing import TypedDict class Point(TypedDict): x: int y: int label: str # alternatively written as: #Point = TypedDict('Point', {'x': int, 'y': int, 'label': str}) # pass a: Point = {'x': 1, 'y': 2, 'label': 'good'} # fail b: Point = {'z': 3, 'label': 'bad'} }}} By default, all attributes in a `TypedDict` are required in order to pass a type checker. Annotate optional attributes with `NotRequired`. {{{ from typing import TypedDict, NotRequired class Point(TypedDict): x: int y: int NotRequired[label]: str }}} The inverse behavior can also be acheived. {{{ from typing import TypedDict, Required class Point(TypedDict, total=False): x: Required[int] y: Required[int] label: str # alternatively written as: #Point = TypedDict('Point', {'x': Required[int], 'y': Required[int], 'label': str}, total=False) }}} `TypedDict` definitions can inherit from other `TypedDict` definitions. {{{ class 3DPoint(Point): z: int }}} To create a `TypedDict` with [[Python/Typing#Generic_Types|generic types]], try: {{{ from typing import TypedDict, Generic, TypeVar T = TypeVar('T') class User(TypedDict, Generic[T]): own_group: T all_groups: list[T] }}} === Union === To annotate an argument that can be multiple types, use `Union`. {{{ from typing import Union def int_or_str(arg: Union[int, str]) -> None: if isinstance(arg, int): # type checkers understand type guards; `arg` is checked as an `int` here arg += 1 else: # type checkers also infer that `arg` is a `str` here arg += "1" }}} If the argument can be either a type or `None`, consider `Optional`. See also the [[Python/Builtins/Operators#Union|union operator]] (`|`). === ValuesView === Do not use `typing.ValuesView[...]` in Python 3.9+; instead use `collections.abc.ValuesView[...]`. See [[Python/Collections/Abc#ValuesView|here]] for more details. ---- == Annotations for Type Hints == The following annotations are mostly useful for visual hints in IDEs. === Annotated === {{{ from typing import Annotated SmallInt = Annotated[int, ValueRange(0, 9)] }}} ---- == Annotations for Annotations == The following annotations are mostly useful for supporting annotations. === Self === For class methods that return an instance of the class, use `Self`. This is superior to using forward references because subclasses will automatically have the correct annotation. {{{ from typing import Self class Foo: def return_self(self) -> Self: return self }}} === TypeGuard === Functions like `isinstance` act as '''type guards'''. Type checkers understand that subsequent conditional logic will only be called if the value is of a known, constrained type. Custom type guards can be written and annotated with `TypeGuard[T]`. If the function returns `True`, then the value is of type `T`. {{{ from typing import TypeGuard def is_str_list(val: list[object]) -> TypeGuard[list[str]]: return all(isinstance(x, str) for x in val) }}} ---- == Functions for Annotations == The following functions are mostly useful for supporting annotations. === Assert_Type === Assert that a value is of a constrained type. {{{ from typing import assert_type def int_or_str(arg: int | str) -> None: if isinstance(arg, int): return assert_type(arg, str) }}} === Cast === Tells the type checker that a value is of a constrained type. At runtime, immediately returns the value. {{{ from typing import cast, TypeVar T = TypeVar('T') def to_int(arg: T) -> int: return case(arg, int) }}} === Clear_Overloads === Remove `@overload` function definitions in runtime. === Get_Args === Inspect special types. {{{ from typing import get_args, Union assert get_args(Union[int, str]) == (int, str) }}} === Get_Origin === Inspect special types. {{{ from typing import get_origin, Union assert get_origin(Union[int, str]) is Union }}} === Get_Type_Hints === Inspect type hints for a function, method, module or class object. This performs some mutation of annotations, such as the evaluation of [[Python/Typing#Forward_References|forward references]]. === Get_Overloads === Inspect the overwritten `@overload` function definitions in runtime. === Is_TypedDict === Checks if a '''type''' is a `TypedDict`. === @No_Type_Check === Decorate objects with `@no_type_check` to tell type checkers that the object should not be checked. With classes it is applied to all methods, attributes, and classes defined within, but not to subclasses or superclasses. === @No_Type_Check_Decorator === Decorate a decorator function with `@no_type_check`. === @Overload === To annotate a function with complex internal logic that returns different types based on the argument types, use the `@overload` decorator. {{{ @overload def process(response: None) -> None: ... @overload def process(response: int) -> tuple[int, str]: ... @overload def process(response: bytes) -> str: ... def process(response): }}} At runtime the preceding definitions of `process()` are overwritten by the final one, erasing them from the namespace. === Reveal_Type === When a type checker reaches a call to `reveal_type()`, it produces diagnostic information. {{{ x: int = 0 reveal_type(x) # "builtins.int" y = reveal_type(1) # "builtins.int" }}} At runtime it prints the value's type (to stderr) and returns it unchanged. === @Type_Check_Only === Decorate objects with `@type_check_only` to indicate that an object is only available to type checkers, and will be unavailable at runtime. ---- == Annotations for Logic Checks == The following annotations are mostly useful for causing a type checker to identify issues with program logic. They may be necessary to satisfy the type checker in edge cases. === ClassVar === If there is a class attribute that should never be set on an instance, annotate with `ClassVar`. {{{ from typing import ClassVar class Quadruped: feet: ClassVar[int] = 4 cat = Quadruped("cat") # fail cat.feet = 3 }}} === Final === If there is a constant that should never be changed, annotate with `Final`. {{{ from typing import Final MAX_CONN: Final[int] = 1 # fail MAX_CONN += 1 }}} === Never === If there is a function that should never be called, annotate the argument with `Never`. {{{ from typing import Never def never_call_me(arg: Never) -> None: pass # fail def do_it_anyway(arg: int | str) -> None: never_call_me(arg) # pass: arg is either int or str so the default case is never reached def int_or_str(arg: int | str) -> None: match arg: case int(): pass case str(): pass case _: never_call_me(arg) }}} === NoReturn === Do not use `NoReturn` in Python 3.11+; instead use `Never`. ---- == Functions for Logic Checks == The following functions are mostly useful for causing a type checker to identify issues with program logic. === Assert_Never === An assertion that, if ever reached, raises an error (both in type checkers and in runtime). {{{ from typing import assert_never def int_or_str(arg: int | str) -> None: match arg: case int(): pass case str(): pass case _ as unreachable: assert_never(unreachable) }}} === @Final === If there is a method that should never be overwritten, decorate it with `@final`. {{{ class Base: @final def done(self) -> None: pass # fail class Sub(Base): def done(self) -> None: pass }}} If there is a class that should never be subclassed, decorate it with `@final`. {{{ @final class Person: ... # fail class Android(Person): ... }}} ---- == Custom Types == To create a custom type, use `NewType`. Type checkers will treat the custom type as a subclass of the original type, while rejecting passed arguments of the original type. {{{ from typing import NewType UserId = NewType('UserId', int) # passes user_a = get_user_name(UserId(42351)) # fails user_b = get_user_name(-1) }}} Given the above example, at runtime, `UserId` returns a callable that immediately returns the original value. This leads to three properties: 1. `UserId(value)` has minimal runtime overhead 2. an instance of `UserId` cannot be returned at runtime; `UserId(value)` immediately evaluates to `value` 3. `UserId` is not subclassable (except by chaining `NewType`: `ProUserId = NewType('ProUserId', UserId)`) ---- == Protocols == `Protocol` is a base class for '''protocols'''. {{{ from typing import Protocol class SomeProtocol(Protocol): def meth(self) -> int: ... class A: def meth(self) -> int: return 0 class B: def meth(self) -> int: return 1 def func(c: SomeProtocol) -> int: return c.meth() # pass func(A()) # pass func(B()) }}} Protocol classes can be [[Python/Typing#Generic_Types|generic]] as well. {{{ from typing import TypeVar, Protocol T = TypeVar('T') class GenericProtocol(Protocol[T]): def meth(self) -> T: ... }}} === @Runtime_Checkable === If a protocol is decorated with `@runtime_checkable`, then it can be used at runtime for `isinstance` and `issubclass` checking. {{{ from typing import Protocol, runtime_checkable @runtime_checkable class Closable(Protocol): def close(self): ... assert isinstance(open('/some/file'), Closable) }}} Note that method type signatures are ''not'' checked; ''only'' the presence of the required methods. This effectively implements duck type checking. === Pre-defined Protocols === The following protocols are defined within the `typing` namespace, with the `@runtime_checkable` decorator. * `SupportsAbs` with `__abs__` that is covariant in its return type * `SupportsBytes` with `__bytes__` * `SupportsComplex` with `__complex__` * `SupportsFloat` with `__float__` * `SupportsIndex` with `__index__` * `SupportsInt` with `__int__` * `SupportsRound` with `__round__` that is covariant in its return type ---- == Generic Types == To annotate a '''generic type''', use `TypeVar`. {{{ from collections.abc import Sequence from typing import TypeVar T = TypeVar('T') def first(l: Sequence[T]) -> T: return l[0] }}} There are additional type constructs for '''variadic generics'''. For example, to constrain the type of the first or last value in a tuple while leaving others alone, use `TypeVarTuple`. {{{ from typing import TypeVar, TypeVarTuple T = TypeVar('T') Ts = TypeVarTuple('Ts') def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]: return (*tup[1:], tup[0]) }}} `TypeVarTuple` is only valid when used with the [[Python/Builtins/Operators#Expansion|expansion operator]]. {{{ from typing import TypeVar, TypeVarTuple T = TypeVar('T') Ts = TypeVarTuple('Ts') # fail x: tuple[Ts] # pass x: tuple[*Ts] }}} In the above context, `*Ts` would be equivalent to using `Unpack[Ts]`. `Unpack` exists because the expansion operator ''formerly'' could not be used in this way. Do not use `Unpack` in Python 3.11+. === Abstract Generic Class === Base classes are constructed like: {{{ from typing import TypeVar, Generic KT = TypeVar('KT') VT = TypeVar('VT') class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... X = TypeVar('X') Y = TypeVar('Y') def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y: try: return mapping[key] except KeyError: return default }}} ---- == Metaprogramming == === @Dataclass_Transform === Decorate objects with `@dataclass_transform` to tell type checkers that the object performs runtime magic. With decorator functions: {{{ from typing import TypeVar, dataclass_transform T = TypeVar("T") @dataclass_transform() def create_model(cls: type[T]) -> type[T]: return cls @create_model class CustomerModel: id: int name: str }}} With base classes: {{{ from typing import dataclass_transform @dataclass_transform() class ModelBase: ... class CustomerModel(ModelBase): id: int name: str }}} With metaclasses: {{{ from typing import dataclass_transform @dataclass_transform() class ModelMeta(type): ... class ModelBase(metaclass=ModelMeta): ... class CustomerModel(ModelBase): id: int name: str }}} === Concatenate and ParamSpec === To annotate a decorator that inserts an argument into a function's argument tuple, use `Concatenate` and `ParamSpec`. {{{ from collections.abc import Callable from threading import Lock from typing import Concatenate, ParamSpec, TypeVar P = ParamSpec('P') R = TypeVar('R') my_lock = Lock() # a thread-safe lock that will be shared by `@with_lock` def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]: def inner(*args: P.args, **kwargs: P.kwargs) -> R: return f(my_lock, *args, **kwargs) return inner @with_lock def sum_threadsafe(lock: Lock, numbers: list[float]) -> float: with lock: return sum(numbers) # pass type checker AND thread-safe at runtime sum_threadsafe([1.1, 2.2, 3.3]) }}} ---- == See also == [[https://docs.python.org/3/library/typing.html|Python typing module documentation]] [[https://typing.readthedocs.io/en/latest/|Python typing guide and reference materials]] ---- CategoryRicottone