How to type hint a generic numeric type in Python?
The currently accepted solution of using Number
is fairly broken considering that, as pointed out in the comments, int
s are not Number
s for static type checkers like mypy and PyRight. The situation has been discussed for years with no clear resolution.
Another possible approach extracted from a detailed explanation from a related question is:
from typing import SupportsFloat as Numeric
which has the following behavior:
from decimal import Decimal
from fractions import Fraction
from typing import SupportsFloat as Numeric
import numpy as np
def f(x: Numeric) -> None:
pass
# Accepted by mypy/Pyright:
f(123)
f(np.uintc(55))
f(Fraction(-3, 2))
f(Decimal("-3.14"))
f(np.array([1, 2, 3])) # Should an array be numeric?
# Results in type errors:
f(complex(2, 3))
f("asdf")
This has the advantage of being fairly permissive, except for complex
. In case you want to include complex
as well, simply do
from typing import SupportsFloat, Union
Numeric = Union[SupportsFloat, complex]
or equivalently in Python ≥3.10 style:
from typing import SupportsFloat, TypeAlias
Numeric: TypeAlias = SupportsFloat | complex
It's perhaps unfortunate that NumPy arrays are considered numeric in the sense of SupportsFloat
, but that illustrates the obscure philosophical nature of the question "what is a number?".
PEP 3141 added abstract base classes for numbers, so you could use:
from numbers import Number
def foo(a: Number) -> Number:
...
There isn't a generic numeric type in the typing
module, so you would have to create such a type with Union
instead:
from typing import Union
numeric = Union[int, float, complex]
...
To add support for Numpy's collection of numeric types, add np.number
to that Union.
numeric = Union[int, float, complex, np.number]