# `numbers` — Clase base abstracta numérica

Código fuente: Lib/numbers.py

El módulo `numbers` (PEP 3141) define una jerarquía de abstract base classes numérico que define progresivamente más operaciones. Ninguno de los tipos definidos en este módulo está destinado a ser instanciado.

class `numbers.``Number`

  La raíz de la jerarquía numérica. Si desea validar si un argumento x es un número, sin importar su tipo, use `isinstance(x, Number)`.

## La torre numérica

class `numbers.``Complex`

  Las subclases de este tipo describen números complejos e incluyen las operaciones que funcionan en el tipo `complex` integrado. Estos son: conversiones a `complex` y `bool`, `real`, `imag`, `+`, `-`, `*`, `/`, `**`, `abs()`, `conjugate()`, `==` y `!=`. Todos excepto `-` y `!=` son abstractos.

  `real`

    Abstracto. Recupera el componente real de este número.

  `imag`

    Abstracto. Recupera el componente imaginario de este número.

  abstractmethod `conjugate`()

    Abstracto. Retorna el complejo conjugado. Por ejemplo, `(1+3j).conjugate() == (1-3j)`.

class `numbers.``Real`

  Para `Complex`, `Real` agrega las operaciones que trabajan con números reales.

  En resumen, estos son: conversiones a `float`, `math.trunc()`, `round()`, `math.floor()`, `math.ceil()`, `divmod()`, `//`, `%`, `<`, `<=`, `>`, y `>=`.

  Real también proporciona valores predeterminados para `complex()`, `real`, `imag`, y `conjugate()`.

class `numbers.``Rational`

  Subtipos `Real` y agrega `numerator` y `denominator` propiedades, que deben estar en los términos más bajos. Con estos, proporciona un valor predeterminado para `float()`.

  `numerator`

    Abstracto.

  `denominator`

    Abstracto.

class `numbers.``Integral`

  Subtipos `Rational` y agrega una conversión a `int`. Proporciona valores predeterminados para `float()`, `numerator` y `denominator`. Agrega métodos abstractos para `pow()` con operaciones de módulo y cadena de bits: `<<`, `>>`, `&`, `^`, `|`, `~`.

## Notas para implementadores de tipos

Los implementadores deben tener cuidado de igualar números iguales y aplicar un hash a los mismos valores. Esto puede ser sutil si hay dos extensiones diferentes de los números reales. Por ejemplo, `fractions.Fraction` implementa `hash()` de la siguiente manera:

    def __hash__(self):
        if self.denominator == 1:
            # Get integers right.
            return hash(self.numerator)
        # Expensive check, but definitely correct.
        if self == float(self):
            return hash(float(self))
        else:
            # Use tuple's hash to avoid a high collision rate on
            # simple fractions.
            return hash((self.numerator, self.denominator))

### Agregar más ABCs numéricos

Por supuesto, hay más ABCs posibles para los números, y esto sería una jerarquía deficiente si se excluye la posibilidad de añadirlos. Puede usar `MyFoo` entre `Complex` y `Real` así:

    class MyFoo(Complex): ...
    MyFoo.register(Real)

### Implementar operaciones aritméticas

Queremos implementar las operaciones aritméticas tal que las operaciones de modo mixto llamen a una implementación cuyo autor conocía los tipos de ambos argumentos, o convertir ambos argumentos al tipo incorporado más cercano antes de hacer la operación. Para subtipos de `Integral`, esto significa que `__add__()` y `__radd__()` tienen que ser definidos como:

    class MyIntegral(Integral):

        def __add__(self, other):
            if isinstance(other, MyIntegral):
                return do_my_adding_stuff(self, other)
            elif isinstance(other, OtherTypeIKnowAbout):
                return do_my_other_adding_stuff(self, other)
            else:
                return NotImplemented

        def __radd__(self, other):
            if isinstance(other, MyIntegral):
                return do_my_adding_stuff(other, self)
            elif isinstance(other, OtherTypeIKnowAbout):
                return do_my_other_adding_stuff(other, self)
            elif isinstance(other, Integral):
                return int(other) + int(self)
            elif isinstance(other, Real):
                return float(other) + float(self)
            elif isinstance(other, Complex):
                return complex(other) + complex(self)
            else:
                return NotImplemented

Hay 5 casos diferentes para una operación de tipo mixto en subclases de `Complex`. Se explicará todo el código anterior que no se refiere a `MyIntegral` y `OtherTypeIKnowAbout` como "repetitivo". ``a` será una instancia de `A`, que es un subtipo de `Complex` (`a: A <: Complex`), y ``b : B <: Complex`. Consideraré `a + b`:

> 1. Si `A` define un `__add__()` que acepta `b`, todo está bien.

> 2. Si `A` recurre al código repetitivo y retorna un valor de `__add__()`, perderíamos la posibilidad de que B defina un `__radd __()` más inteligente, por lo que el código repetitivo debería retornar `NotImplemented` de `__add__()`. (O `A` no puede implementar `__add__()` en absoluto.)

> 3. Entonces `B`’s `__radd__()` tiene una oportunidad. Si acepta `a`, todo esta bien.

> 4. Si se vuelve a caer en el código repetitivo, no hay más posibles métodos para probar, por lo que acá debería vivir la implementación predeterminada.

> 5. Si `B <: A`, Python probara `B.__radd__` antes que `A.__add__`. Esto está bien, porque se implementó con conocimiento de `A`, por lo que puede manejar instancias antes de delegar un `Complex`.

Si `A <: Complex` y `B <: Real` sin compartir ningún otro conocimiento,la operación compartida apropiada es la que involucra la clase `complex` incorporada, y ambos `__radd__()` desencadenan allí, entonces `a+b == b+a`.

Dado que la mayoría de las operaciones en un tipo determinado serán muy similares, puede ser útil definir una función auxiliar que genere las instancias forward y reverse de cualquier operador dado. Por ejemplo, `fractions.Fraction` así:

    def _operator_fallbacks(monomorphic_operator, fallback_operator):
        def forward(a, b):
            if isinstance(b, (int, Fraction)):
                return monomorphic_operator(a, b)
            elif isinstance(b, float):
                return fallback_operator(float(a), b)
            elif isinstance(b, complex):
                return fallback_operator(complex(a), b)
            else:
                return NotImplemented
        forward.__name__ = '__' + fallback_operator.__name__ + '__'
        forward.__doc__ = monomorphic_operator.__doc__

        def reverse(b, a):
            if isinstance(a, Rational):
                # Includes ints.
                return monomorphic_operator(a, b)
            elif isinstance(a, numbers.Real):
                return fallback_operator(float(a), float(b))
            elif isinstance(a, numbers.Complex):
                return fallback_operator(complex(a), complex(b))
            else:
                return NotImplemented
        reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
        reverse.__doc__ = monomorphic_operator.__doc__

        return forward, reverse

    def _add(a, b):
        """a + b"""
        return Fraction(a.numerator * b.denominator +
                        b.numerator * a.denominator,
                        a.denominator * b.denominator)

    __add__, __radd__ = _operator_fallbacks(_add, operator.add)

    # ...