Numerary
Numerary is a Python library that provides a set of type-hinting protocols (e.g., `Integer`, `Float`, `Real`, `Complex`, `Number`) designed for more precise and robust type-checking of numeric types in Python. It is currently at version 0.4.4 and is under active development with frequent, smaller updates.
Common errors
-
TypeError: Argument 1 to "my_function" has incompatible type "str"; expected "Number"
cause Attempting to pass a non-numeric type (e.g., a string, list, or None) to a function or variable annotated with a `numerary` numeric protocol like `Number`, `Integer`, or `Float`.fixEnsure that the value being passed or assigned is an instance of a Python numeric type (`int`, `float`, `complex`) or a custom class that correctly implements the required `numerary` protocol. -
TypeError: Argument of type "int" cannot be assigned to parameter "x" of type "float"
cause When using strict type checkers (like MyPy in certain configurations), assigning an `int` to a variable or parameter explicitly typed as `float` can raise an error. While Python allows implicit conversion, type checkers might flag this depending on context.fixIf you intend to accept both `int` and `float` values, use `numerary.Float` as the type hint for the parameter or variable, as `numerary.Float` is a protocol satisfied by both `int` and `float`.
Warnings
- breaking Numerary is pre-1.0.0, meaning its API may still undergo breaking changes in minor versions. While efforts are made to maintain compatibility, users should review release notes when upgrading.
- gotcha Numerary protocols are `typing.Protocol`s. They define interfaces for numeric types, primarily for static type checking (e.g., MyPy) and runtime `isinstance` checks when decorated with `@runtime_checkable` (which `numerary` does). They do not modify Python's built-in numeric types, but rather describe properties they satisfy.
- gotcha The `numerary.Float` protocol (like `numbers.Real`) is satisfied by both `int` and `float` built-in types. If you need to strictly differentiate between `int` and `float` instances at runtime (i.e., accept only `float` and not `int`), use `isinstance(obj, float)` directly rather than `isinstance(obj, numerary.Float)`.
Install
-
pip install numerary
Imports
- Integer
from numerary import Integer
- Float
from numerary import Float
- Real
from numerary import Real
- Complex
from numerary import Complex
- Number
from numerary import Number
Quickstart
from numerary import Integer, Float, Real, Number
def process_number(n: Number) -> str:
if isinstance(n, Integer):
return f"It's an integer: {n} (type: {type(n).__name__})"
elif isinstance(n, Float):
return f"It's a float: {n} (type: {type(n).__name__})"
elif isinstance(n, Real):
return f"It's a real number: {n} (type: {type(n).__name__})"
else:
return f"It's a generic number: {n} (type: {type(n).__name__})"
print(process_number(5))
print(process_number(5.0))
print(process_number(3 + 4j))
print(process_number(10.5))