numbers
— Numeriska abstrakta basklasser¶
Källkod: Lib/numbers.py
Modulen numbers
(PEP 3141) definierar en hierarki av numeriska abstrakta basklasser som successivt definierar fler operationer. Ingen av de typer som definieras i denna modul är avsedda att instansieras.
- class numbers.Number¶
Roten i den numeriska hierarkin. Om du bara vill kontrollera om ett argument x är ett tal, utan att bry dig om vilken typ, använd
isinstance(x, Number)
.
Det numeriska tornet¶
- class numbers.Complex¶
Subklasser av denna typ beskriver komplexa tal och innehåller de operationer som fungerar på den inbyggda typen
complex
. Dessa är: konverteringar tillcomplex
ochbool
,real
,imag
,+
,-
,*
,/
,**
,abs()
,conjugate()
,==
och!=
. Alla utom-
och!=
är abstrakta.- real¶
Sammanfattning. Hämtar den reella komponenten i detta tal.
- imag¶
Sammanfattning. Hämtar den imaginära komponenten i detta tal.
- abstractmethod conjugate()¶
Sammanfattning. Returnerar den komplexa konjugaten. Till exempel,
(1+3j).conjugate() == (1-3j)
.
- class numbers.Real¶
Till
Complex
läggerReal
till de operationer som fungerar på reella tal.I korthet är dessa: en konvertering till
float
,math.trunc()
,round()
,math.floor()
,math.ceil()
,divmod()
,//
,%
,<
,<=
,>
och>=
.Real innehåller också standardvärden för
complex()
,real
,imag
ochconjugate()
.
- class numbers.Rational¶
Subtyp av
Real
och lägger till egenskapernanumerator
ochdenominator
. Det ger också en standard förfloat()
.Värdena
numerator
ochdenominator
ska vara instanser avIntegral
och ska vara i lägsta termer meddenominator
positiv.- numerator¶
Sammanfattning.
- denominator¶
Sammanfattning.
Anmärkningar för typimplementerare¶
Implementatörer bör vara noga med att göra lika tal lika och hasha dem till samma värden. Detta kan vara subtilt om det finns två olika utvidgningar av de reella talen. Till exempel fractions.Fraction
implementerar hash()
enligt följande:
def __hash__(self):
if self.denominator == 1:
# Gör heltal rätt.
return hash(self.numerator)
# Dyr kontroll, men definitivt korrekt.
om self == float(self):
returnera hash(float(self))
else:
# Använd tupels hash för att undvika en hög kollisionsfrekvens på
# enkla fraktioner.
return hash((self.numerator, self.denominator))
Lägga till fler numeriska ABC¶
Det finns naturligtvis fler möjliga ABC för tal, och detta skulle vara en dålig hierarki om den uteslöt möjligheten att lägga till dessa. Du kan lägga till MyFoo
mellan Complex
och Real
med:
klass MyFoo(Komplex): ...
MyFoo.register(Real)
Implementering av aritmetiska operationer¶
Vi vill implementera de aritmetiska operationerna så att operationer i blandade lägen antingen anropar en implementation vars författare kände till typerna för båda argumenten, eller konverterar båda till närmaste inbyggda typ och utför operationen där. För subtyper av Integral
innebär detta att __add__()
och __radd__()
bör definieras som:
klass 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 Inte implementerad
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 komplex(annan) + komplex(själv)
else:
return Ej implementerad
Det finns 5 olika fall för en mixed-type operation på subklasser av Complex
. Jag kommer att referera till all ovanstående kod som inte refererar till MyIntegral
och OtherTypeIKnowAbout
som ”boilerplate”. a
kommer att vara en instans av A
, som är en subtyp av Complex
(a : A <: Complex
), och b : B <: Complex
. Jag kommer att överväga a + b
:
Om
A
definierar en__add__()
som accepterarb
, är allt väl.Om
A
faller tillbaka till boilerplate koden, och det skulle returnera ett värde från__add__()
, skulle vi missa möjligheten attB
definierar en mer intelligent__radd__()
, så boilerplate bör returneraNotImplemented
från__add__()
. (Eller så kanskeA
inte implementerar__add__`()
alls.)Då får
B
:s__radd__()
en chans. Om den accepterara
är allt bra.Om den faller tillbaka på standardutformningen finns det inga fler möjliga metoder att prova, så det är här standardimplementeringen ska finnas.
Om
B <: A
, försöker PythonB.__radd__
föreA.__add__
. Detta är ok, eftersom det implementerades med kunskap omA
, så det kan hantera dessa instanser innan det delegeras tillComplex`
.
Om A <: Complex
och B <: Real
utan att dela någon annan kunskap, så är den lämpliga delade operationen den som involverar den inbyggda complex`
, och båda __radd__`()
landar där, så a+b == b+a
.
Eftersom de flesta operationer på en viss typ kommer att vara mycket lika kan det vara användbart att definiera en hjälpfunktion som genererar de framåtriktade och bakåtriktade instanserna av en viss operator. Till exempel använder fractions.Fraction
:
def _operator_fallbacks(monomorf_operator, fallback_operator):
def forward(a, b):
if isinstance(b, (int, Fraktion)):
return monomorfisk_operator(a, b)
elif isinstance(b, float):
return fallback_operator(float(a), b)
elif isinstance(b, komplex):
return fallback_operator(komplex(a), b)
else:
return Ej implementerad
forward.__name__ = '__' + fallback_operator.__name__ + '__'
forward.__doc__ = monomorphic_operator.__doc__
def reverse(b, a):
if isinstance(a, Rational):
# Inkluderar ints.
return monomorfisk_operator(a, b)
elif isinstance(a, Real):
return fallback_operator(float(a), float(b))
elif isinstance(a, Komplex):
return fallback_operator(komplex(a), komplex(b))
else:
return Inte implementerad
reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
reverse.__doc__ = monomorphic_operator.__doc__
returnera framåt, bakåt
def _add(a, b):
"""a + b"""
return Fraktion(a.täljare * b.nämnare + b.täljare * a.nämnare
b.täljare * a.nämnare,
a.nämnare * b.nämnare)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...