Python’s numbers module defines the Numeric Tower: a hierarchy of Abstract Base Classes (ABCs) for numeric types. import numbers. Hierarchy (most general → most specific): Number → Complex → Real → Rational → Integral. isinstance(x, numbers.Number) — True for int, float, complex, Decimal, Fraction. isinstance(x, numbers.Integral) — True for int only (not float). isinstance(x, numbers.Real) — True for int, float (not complex). isinstance(x, numbers.Rational) — True for int, Fraction (not float). isinstance(x, numbers.Complex) — True for int, float, complex. Abstract methods Complex must implement: __complex__, real, imag, __abs__, conjugate, __pos__, __neg__, __add__, __radd__, __mul__, __rmul__, __truediv__, __rtruediv__, __pow__, __rpow__, __eq__. Real adds: __float__, __trunc__, __floor__, __ceil__, __round__, __floordiv__, __rfloordiv__, __mod__, __rmod__, __lt__, __le__. Integral adds: __int__, __index__, __lshift__, __rshift__, __and__, __or__, __xor__, __invert__. Register: numbers.Real.register(MyFloat) — make existing class satisfy ABC without inheriting. Claude Code generates duck-typed numeric validators, custom numeric types, and numeric tower walk utilities.
CLAUDE.md for numbers
## numbers Stack
- Stdlib: import numbers
- Check: isinstance(x, numbers.Number) # any numeric
isinstance(x, numbers.Integral) # int-like
isinstance(x, numbers.Real) # float/int, not complex
isinstance(x, numbers.Rational) # Fraction/int
isinstance(x, numbers.Complex) # complex/float/int
- Custom: class MyNum(numbers.Real): ... (implement all abstractmethods)
- Register: numbers.Real.register(MyFloat)
numbers Numeric Tower Pipeline
# app/numbersutil.py — type-check, tower walk, custom Rational, validators, dispatch
from __future__ import annotations
import math
import numbers
import operator
from dataclasses import dataclass
from fractions import Fraction
from typing import Any, Callable, TypeVar
N = TypeVar("N", bound=numbers.Number)
# ─────────────────────────────────────────────────────────────────────────────
# 1. Numeric type inspection helpers
# ─────────────────────────────────────────────────────────────────────────────
def numeric_level(x: Any) -> str:
"""
Return the most-specific numbers ABC name for x.
Example:
numeric_level(5) # "Integral"
numeric_level(3.14) # "Real"
numeric_level(Fraction(1,3))# "Rational"
numeric_level(1+2j) # "Complex"
numeric_level("hi") # "not-numeric"
"""
if isinstance(x, numbers.Integral):
return "Integral"
if isinstance(x, numbers.Rational):
return "Rational"
if isinstance(x, numbers.Real):
return "Real"
if isinstance(x, numbers.Complex):
return "Complex"
if isinstance(x, numbers.Number):
return "Number"
return "not-numeric"
def tower_membership(x: Any) -> dict[str, bool]:
"""
Return dict showing which ABC levels x belongs to.
Example:
tower_membership(42)
# {"Number": True, "Complex": True, "Real": True, "Rational": True, "Integral": True}
tower_membership(3.14)
# {"Number": True, "Complex": True, "Real": True, "Rational": False, "Integral": False}
"""
return {
"Number": isinstance(x, numbers.Number),
"Complex": isinstance(x, numbers.Complex),
"Real": isinstance(x, numbers.Real),
"Rational": isinstance(x, numbers.Rational),
"Integral": isinstance(x, numbers.Integral),
}
def is_numeric(x: Any) -> bool:
"""Return True if x is any numeric type in the tower."""
return isinstance(x, numbers.Number)
def is_integer_valued(x: Any) -> bool:
"""
Return True if x is an integer-valued number (int, Integral,
or a float/Decimal with no fractional part).
Example:
is_integer_valued(5) # True
is_integer_valued(5.0) # True
is_integer_valued(5.1) # False
"""
if isinstance(x, numbers.Integral):
return True
if isinstance(x, numbers.Real):
return float(x) == math.floor(float(x))
return False
def require_numeric(x: Any, label: str = "value") -> numbers.Number:
"""
Assert x is numeric, raise TypeError with a helpful message otherwise.
Example:
require_numeric(42) # → 42
require_numeric("oops") # raises TypeError
"""
if not isinstance(x, numbers.Number):
raise TypeError(
f"{label} must be a number (got {type(x).__name__!r}: {x!r})"
)
return x
def require_real(x: Any, label: str = "value") -> numbers.Real:
"""Assert x is a real number (no imaginary part)."""
if not isinstance(x, numbers.Real):
raise TypeError(
f"{label} must be a real number (got {type(x).__name__!r}: {x!r})"
)
return x
def require_integral(x: Any, label: str = "value") -> numbers.Integral:
"""Assert x is integral."""
if not isinstance(x, numbers.Integral):
raise TypeError(
f"{label} must be an integer (got {type(x).__name__!r}: {x!r})"
)
return x
# ─────────────────────────────────────────────────────────────────────────────
# 2. Numeric dispatch
# ─────────────────────────────────────────────────────────────────────────────
def numeric_dispatch(
x: Any,
on_integral: Callable,
on_rational: Callable,
on_real: Callable,
on_complex: Callable,
on_other: Callable | None = None,
) -> Any:
"""
Dispatch a function based on the numeric tower level of x.
Example:
def describe(x):
return numeric_dispatch(x,
on_integral=lambda v: f"integer {v}",
on_rational=lambda v: f"rational {v}",
on_real=lambda v: f"real {v:.4f}",
on_complex=lambda v: f"complex {v}",
on_other=lambda v: f"not a number",
)
"""
if isinstance(x, numbers.Integral):
return on_integral(x)
if isinstance(x, numbers.Rational):
return on_rational(x)
if isinstance(x, numbers.Real):
return on_real(x)
if isinstance(x, numbers.Complex):
return on_complex(x)
if on_other:
return on_other(x)
raise TypeError(f"not a number: {x!r}")
# ─────────────────────────────────────────────────────────────────────────────
# 3. Minimal custom Real implementation
# ─────────────────────────────────────────────────────────────────────────────
class FixedPoint(numbers.Rational):
"""
A simple fixed-point rational number: stores value as (numerator, denominator).
Implements the full numbers.Rational ABC so it participates in the tower.
Example:
x = FixedPoint(1, 3) # 1/3
y = FixedPoint(1, 6) # 1/6
print(x + y) # FixedPoint(1/2)
print(float(x)) # 0.3333...
isinstance(x, numbers.Rational) # True
"""
def __init__(self, numerator: int, denominator: int = 1) -> None:
if denominator == 0:
raise ZeroDivisionError("denominator cannot be zero")
# Normalize sign and reduce
g = math.gcd(abs(numerator), abs(denominator))
sign = -1 if (numerator < 0) ^ (denominator < 0) else 1
self._num = sign * abs(numerator) // g
self._den = abs(denominator) // g
@property
def numerator(self) -> int:
return self._num
@property
def denominator(self) -> int:
return self._den
# ── arithmetic ────────────────────────────────────────────────────────────
def _coerce(self, other: Any) -> "FixedPoint":
if isinstance(other, FixedPoint):
return other
if isinstance(other, numbers.Integral):
return FixedPoint(int(other))
if isinstance(other, numbers.Rational):
return FixedPoint(other.numerator, other.denominator)
return NotImplemented
def __add__(self, other):
o = self._coerce(other)
if o is NotImplemented:
return NotImplemented
return FixedPoint(self._num * o._den + o._num * self._den, self._den * o._den)
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
o = self._coerce(other)
if o is NotImplemented:
return NotImplemented
return FixedPoint(self._num * o._den - o._num * self._den, self._den * o._den)
def __rsub__(self, other):
return (-self).__add__(other)
def __mul__(self, other):
o = self._coerce(other)
if o is NotImplemented:
return NotImplemented
return FixedPoint(self._num * o._num, self._den * o._den)
def __rmul__(self, other):
return self.__mul__(other)
def __truediv__(self, other):
o = self._coerce(other)
if o is NotImplemented:
return NotImplemented
return FixedPoint(self._num * o._den, self._den * o._num)
def __rtruediv__(self, other):
o = self._coerce(other)
if o is NotImplemented:
return NotImplemented
return FixedPoint(o._num * self._den, o._den * self._num)
def __pow__(self, exp):
if isinstance(exp, numbers.Integral) and int(exp) >= 0:
return FixedPoint(self._num ** int(exp), self._den ** int(exp))
return float(self) ** float(exp)
def __rpow__(self, base):
return float(base) ** float(self)
def __neg__(self):
return FixedPoint(-self._num, self._den)
def __pos__(self):
return FixedPoint(self._num, self._den)
def __abs__(self):
return FixedPoint(abs(self._num), self._den)
# ── comparison ────────────────────────────────────────────────────────────
def __eq__(self, other):
if isinstance(other, FixedPoint):
return self._num == other._num and self._den == other._den
if isinstance(other, numbers.Rational):
return self._num * other.denominator == other.numerator * self._den
return float(self) == float(other)
def __lt__(self, other):
if isinstance(other, FixedPoint):
return self._num * other._den < other._num * self._den
return float(self) < float(other)
def __le__(self, other):
return self == other or self < other
# ── conversions ───────────────────────────────────────────────────────────
def __float__(self):
return self._num / self._den
def __int__(self):
return self._num // self._den
def __bool__(self):
return self._num != 0
def __complex__(self):
return complex(float(self))
def __floor__(self):
return math.floor(self._num / self._den)
def __ceil__(self):
return math.ceil(self._num / self._den)
def __round__(self, ndigits=None):
return round(float(self), ndigits)
def __trunc__(self):
return math.trunc(float(self))
def __floordiv__(self, other):
return int(self / other)
def __rfloordiv__(self, other):
return int(other / self)
def __mod__(self, other):
return float(self) % float(other)
def __rmod__(self, other):
return float(other) % float(self)
def __repr__(self) -> str:
if self._den == 1:
return f"FixedPoint({self._num})"
return f"FixedPoint({self._num}/{self._den})"
def __hash__(self):
return hash(float(self))
# ─────────────────────────────────────────────────────────────────────────────
# 4. Numeric summary utility
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class NumericSummary:
value: Any
type_name: str
tower_level: str
is_finite: bool
is_integer_valued: bool
as_float: float | None
def __str__(self) -> str:
return (
f"{self.value!r:20s} "
f"type={self.type_name:12s} "
f"level={self.tower_level:10s} "
f"finite={self.is_finite} "
f"int_val={self.is_integer_valued}"
)
def summarize(x: Any) -> NumericSummary:
"""
Produce a NumericSummary for any value.
Example:
print(summarize(42))
print(summarize(Fraction(1, 3)))
print(summarize(float("inf")))
"""
is_num = isinstance(x, numbers.Number)
try:
as_float: float | None = float(x) if isinstance(x, numbers.Real) else None
except (TypeError, ValueError):
as_float = None
finite = False
if as_float is not None:
finite = math.isfinite(as_float)
return NumericSummary(
value=x,
type_name=type(x).__name__,
tower_level=numeric_level(x),
is_finite=finite,
is_integer_valued=is_integer_valued(x) if is_num else False,
as_float=as_float,
)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
from decimal import Decimal
print("=== numbers demo ===")
# ── tower membership ───────────────────────────────────────────────────────
print("\n--- tower_membership ---")
samples = [42, 3.14, Fraction(1, 3), 1 + 2j, Decimal("2.5"), "text"]
for v in samples:
print(f" {v!r:20s}: {numeric_level(v):12s} {tower_membership(v)}")
# ── require_* validators ───────────────────────────────────────────────────
print("\n--- require_* ---")
try:
require_integral(3.5, "count")
except TypeError as e:
print(f" TypeError: {e}")
print(f" require_integral(7) ok: {require_integral(7)}")
# ── numeric_dispatch ───────────────────────────────────────────────────────
print("\n--- numeric_dispatch ---")
def _describe(x: Any) -> str:
return numeric_dispatch(
x,
on_integral=lambda v: f"integer {v}",
on_rational=lambda v: f"rational {float(v):.4f}",
on_real=lambda v: f"real {float(v):.4f}",
on_complex=lambda v: f"complex {v}",
on_other=lambda v: f"not-number",
)
for v in [7, Fraction(2, 3), 3.14, 1 + 2j, "x"]:
print(f" {v!r:20s} → {_describe(v)}")
# ── FixedPoint ─────────────────────────────────────────────────────────────
print("\n--- FixedPoint (custom numbers.Rational) ---")
a = FixedPoint(1, 3)
b = FixedPoint(1, 6)
print(f" {a} + {b} = {a + b}")
print(f" {a} * {b} = {a * b}")
print(f" {a} / {b} = {a / b}")
print(f" float({a}) = {float(a):.6f}")
print(f" isinstance(FixedPoint(1,3), numbers.Rational): "
f"{isinstance(a, numbers.Rational)}")
print(f" isinstance(FixedPoint(1,3), numbers.Real): "
f"{isinstance(a, numbers.Real)}")
# ── summarize ──────────────────────────────────────────────────────────────
print("\n--- summarize ---")
for v in [42, 3.14, float("inf"), Fraction(2, 3), Decimal("1.5"),
1 + 0j, FixedPoint(3, 4)]:
print(f" {summarize(v)}")
print("\n=== done ===")
For the fractions.Fraction alternative — fractions.Fraction is the concrete stdlib class that implements numbers.Rational for exact rational arithmetic; Fraction(1, 3) + Fraction(1, 6) == Fraction(1, 2) with no floating-point rounding — use Fraction directly when you need exact rational calculations; use the numbers ABCs when writing code that should accept any rational-like type (your own or a third-party numeric type) without hardcoding a specific class. For the typing.SupportsInt / typing.SupportsFloat alternative — typing.SupportsInt, SupportsFloat, SupportsComplex, and SupportsRound are protocol-based alternatives to the numeric tower for type-annotation purposes; they check for the presence of __int__(), __float__() etc. at static analysis time without requiring inheritance — use SupportsFloat in type hints where any object with __float__() is acceptable; use numbers.Real at runtime with isinstance() when you need a richer guarantee (ordering, floor, ceil, mod) that protocols don’t enforce. The Claude Skills 360 bundle includes numbers skill sets covering numeric_level()/tower_membership() inspection tools, is_numeric()/is_integer_valued()/require_numeric()/require_real()/require_integral() validators, numeric_dispatch() tower-level dispatcher, FixedPoint complete numbers.Rational implementation with all abstract methods, and NumericSummary dataclass with summarize(). Start with the free tier to try numeric ABC patterns and numbers tower code generation.