numbers — Numerische abstrakte Basisklassen¶
Quellcode: Lib/numbers.py
Das Modul numbers (PEP 3141) definiert eine Hierarchie von numerischen abstrakten Basisklassen, die schrittweise mehr Operationen definieren. Keiner der in diesem Modul definierten Typen ist zur Instanziierung vorgesehen.
- class numbers.Number¶
Die Wurzel der numerischen Hierarchie. Wenn Sie nur prüfen möchten, ob ein Argument x eine Zahl ist, ohne sich um die Art zu kümmern, verwenden Sie
isinstance(x, Number).
Der numerische Turm¶
- class numbers.Complex¶
Unterklassen dieses Typs beschreiben komplexe Zahlen und umfassen die Operationen, die auf dem integrierten Typ
complexfunktionieren. Dies sind: Konvertierungen nachcomplexundbool,real,imag,+,-,*,/,**,abs(),conjugate(),==und!=. Alle außer-und!=sind abstrakt.- real¶
Abstrakt. Ruft die reelle Komponente dieser Zahl ab.
- imag¶
Abstrakt. Ruft die imaginäre Komponente dieser Zahl ab.
- abstractmethod conjugate()¶
Abstrakt. Gibt die komplexe Konjugierte zurück. Zum Beispiel:
(1+3j).conjugate() == (1-3j).
- class numbers.Real¶
Zu
ComplexfügtRealdie Operationen hinzu, die auf reellen Zahlen funktionieren.Kurz gesagt, dies sind: eine Konvertierung nach
float,math.trunc(),round(),math.floor(),math.ceil(),divmod(),//,%,<,<=,>und>=.Real stellt auch Standardimplementierungen für
complex(),real,imagundconjugate()bereit.
- class numbers.Rational¶
Unterteilt
Realund fügt die Eigenschaftennumeratorunddenominatorhinzu. Es stellt auch eine Standardimplementierung fürfloat()bereit.Die Werte
numeratorunddenominatorsollten Instanzen vonIntegralsein und auf ihre niedrigsten Terme reduziert sein, wobeidenominatorpositiv ist.- numerator¶
Abstrakt. Der Zähler dieser rationalen Zahl.
- denominator¶
Abstrakt. Der Nenner dieser rationalen Zahl.
Hinweise für Implementierer¶
Implementierer sollten darauf achten, gleiche Zahlen auch als gleich zu behandeln und ihnen gleiche Hash-Werte zuzuweisen. Dies kann subtil sein, wenn es zwei verschiedene Erweiterungen der reellen Zahlen gibt. Zum Beispiel implementiert fractions.Fraction hash() wie folgt
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))
Hinzufügen weiterer numerischer ABCs¶
Es gibt natürlich weitere mögliche ABCs für Zahlen, und dies wäre eine schlechte Hierarchie, wenn sie die Möglichkeit, diese hinzuzufügen, ausschließen würde. Sie können MyFoo zwischen Complex und Real einfügen mit
class MyFoo(Complex): ...
MyFoo.register(Real)
Implementierung der arithmetischen Operationen¶
Wir möchten die arithmetischen Operationen so implementieren, dass gemischte Operationen entweder eine Implementierung aufrufen, deren Autor die Typen beider Argumente kannte, oder beide in den nächstgelegenen eingebauten Typ konvertieren und die Operation dort durchführen. Für Unterklassen von Integral bedeutet dies, dass __add__() und __radd__() wie folgt definiert werden sollten
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
Es gibt 5 verschiedene Fälle für eine gemischte Typoperation auf Unterklassen von Complex. Ich werde mich auf den gesamten obigen Code beziehen, der nicht auf MyIntegral und OtherTypeIKnowAbout verweist, als „Boilerplate“. a ist eine Instanz von A, die eine Unterklasse von Complex ist (a : A <: Complex), und b : B <: Complex. Ich werde a + b betrachten.
Wenn
Aeine__add__()definiert, diebakzeptiert, ist alles in Ordnung.Wenn
Aauf den Boilerplate-Code zurückfällt und einen Wert von__add__()zurückgeben würde, würden wir die Möglichkeit verpassen, dassBeine intelligentere__radd__()definiert, daher sollte der Boilerplate-CodeNotImplementedvon__add__()zurückgeben. (OderAimplementiert__add__()gar nicht.)Dann erhält die
__radd__()vonBeine Chance. Wenn sieaakzeptiert, ist alles in Ordnung.Wenn sie auf den Boilerplate-Code zurückfällt, gibt es keine weiteren möglichen Methoden mehr zu versuchen, also ist hier die Standardimplementierung angesiedelt.
Wenn
B <: A, versucht PythonB.__radd__vorA.__add__. Das ist in Ordnung, da sie mit Wissen überAimplementiert wurde, kann sie diese Instanzen behandeln, bevor sie anComplexdelegiert.
Wenn A <: Complex und B <: Real ohne weiteres Wissen, dann ist die entsprechende gemeinsame Operation diejenige, die den eingebauten complex-Typ verwendet, und beide __radd__()s landen dort, sodass a+b == b+a.
Da die meisten Operationen auf einem bestimmten Typ sehr ähnlich sein werden, kann es nützlich sein, eine Hilfsfunktion zu definieren, die die Vorwärts- und Rückwärtsinstanzen eines beliebigen Operators erzeugt. Zum Beispiel verwendet fractions.Fraction
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, Real):
return fallback_operator(float(a), float(b))
elif isinstance(a, 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)
# ...