"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

   Subtypes "Real" and adds "numerator" and "denominator" properties.
   It also provides a default for "float()".

   The "numerator" and "denominator" values should be instances of
   "Integral" and should be in lowest terms with "denominator"
   positive.

   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)

   # ...
