Any
represents an unknown static type.
Every type is :term:`assignable` to Any
, and Any
is assignable to every
type.
See :ref:`type-system-concepts` for more discussion of Any
.
A function parameter without an annotation is assumed to be annotated with
Any
. If a generic type is used without specifying type parameters,
they are assumed to be Any
:
from collections.abc import Mapping def use_map(m: Mapping) -> None: # Same as Mapping[Any, Any] ...
This rule also applies to tuple
, in annotation context it is equivalent
to tuple[Any, ...]
. As well, a bare
Callable
in an annotation is equivalent to Callable[..., Any]
:
from collections.abc import Callable def check_args(args: tuple) -> bool: ... check_args(()) # OK check_args((42, 'abc')) # Also OK check_args(3.14) # Flagged as error by a type checker # A list of arbitrary callables is accepted by this function def apply_callbacks(cbs: list[Callable]) -> None: ...
Any
can also be used as a base class. This can be useful for
avoiding type checker errors with classes that can duck type anywhere or
are highly dynamic.
When used in a type hint, the expression None
is considered
equivalent to type(None)
.
The typing
module provides a :term:`special form` NoReturn
to annotate functions
that never return normally. For example, a function that unconditionally
raises an exception:
from typing import NoReturn def stop() -> NoReturn: raise RuntimeError('no way')
The NoReturn
annotation is used for functions such as sys.exit
.
Static type checkers will ensure that functions annotated as returning
NoReturn
truly never return, either implicitly or explicitly:
import sys from typing import NoReturn def f(x: int) -> NoReturn: # Error, f(0) implicitly returns None if x != 0: sys.exit(1)
The checkers will also recognize that the code after calls to such functions is unreachable and will behave accordingly:
# continue from first example def g(x: int) -> int: if x > 0: return x stop() return 'whatever works' # Error might be not reported by some checkers # that ignore errors in unreachable blocks
Since Python 3.11, the typing
module contains a :term:`special form`
Never
. It represents the bottom type, a type that represents the empty set
of Python objects.
The Never
type is equivalent to NoReturn
, which is discussed above.
The NoReturn
type is conventionally used in return annotations of
functions, and Never
is typically used in other locations, but the two
types are completely interchangeable.
Python's numeric types complex
, float
and int
are not
subtypes of each other, but to support common use cases, the type
system contains a straightforward shortcut:
when an argument is annotated as having
type float
, an argument of type int
is acceptable; similar,
for an argument annotated as having type complex
, arguments of
type float
or int
are acceptable.
Sometimes you want to talk about class objects, in particular class
objects that inherit from a given class. This can be spelled as
type[C]
where C
is a class. To clarify: while C
(when
used as an annotation) refers to instances of class C
, type[C]
refers to subclasses of C
. (This is a similar distinction as
between object
and type
.)
For example, suppose we have the following classes:
class User: ... # Abstract base for User classes class BasicUser(User): ... class ProUser(User): ... class TeamUser(User): ...
And suppose we have a function that creates an instance of one of these classes if you pass it a class object:
def new_user(user_class): user = user_class() # (Here we could write the user object to a database) return user
Without subscripting type[]
the best we could do to annotate new_user()
would be:
def new_user(user_class: type) -> User: ...
However using type[]
and a type variable with an upper bound we
can do much better:
U = TypeVar('U', bound=User) def new_user(user_class: type[U]) -> U: ...
Now when we call new_user()
with a specific subclass of User
a
type checker will infer the correct type of the result:
joe = new_user(BasicUser) # Inferred type is BasicUser
The value corresponding to type[C]
must be an actual class object
that's a subtype of C
, not a :term:`special form` or other kind of type.
In other words, in the
above example calling e.g. new_user(BasicUser | ProUser)
is
rejected by the type checker (in addition to failing at runtime
because you can't instantiate a union).
Note that it is legal to use a union of classes as the parameter for
type[]
, as in:
def new_non_team_user(user_class: type[BasicUser | ProUser]): user = new_user(user_class) ...
type[]
distributes over unions:
type[A | B]
is :term:`equivalent` to type[A] | type[B]
.
However, the actual argument passed in at runtime must still be a concrete class object, e.g. in the above example:
new_non_team_user(ProUser) # OK new_non_team_user(TeamUser) # Disallowed by type checker
type[Any]
is also supported (see below for its meaning).
type[T]
where T
is a type variable is allowed when annotating the
first argument of a class method (see the relevant section).
Any other special constructs like tuple
or Callable
are not allowed
as an argument to type
.
There are some concerns with this feature: for example when
new_user()
calls user_class()
this implies that all subclasses
of User
must support this in their constructor signature. However
this is not unique to type[]
: class methods have similar concerns.
A type checker ought to flag violations of such assumptions, but by
default constructor calls that match the constructor signature in the
indicated base class (User
in the example above) should be
allowed. A program containing a complex or extensible class hierarchy
might also handle this by using a factory class method.
When type
is parameterized it requires exactly one parameter.
Plain type
without brackets, the root of Python's metaclass
hierarchy, is equivalent to type[Any]
.
Regarding the behavior of type[Any]
(or type
),
accessing attributes of a variable with this type only provides
attributes and methods defined by type
(for example,
__repr__()
and __mro__
). Such a variable can be called with
arbitrary arguments, and the return type is Any
.
type
is covariant in its parameter, because type[Derived]
is a
subtype of type[Base]
:
def new_pro_user(pro_user_class: type[ProUser]): user = new_user(pro_user_class) # OK ...