numbers
— 數值抽象基類¶
原始碼: Lib/numbers.py
numbers
模組(PEP 3141)定義了一個數值抽象基類的層次結構,它們逐步定義了更多的操作。此模組中定義的任何型別都不應被例項化。
- class numbers.Number¶
數值層次結構的根。如果您只想檢查引數 x 是否是一個數字,而不關心具體型別,請使用
isinstance(x, Number)
。
數值塔¶
- class numbers.Complex¶
此型別的子類描述複數,幷包含對內建
complex
型別進行操作的運算。這些運算包括:轉換為complex
和bool
,real
,imag
,+
,-
,*
,/
,**
,abs()
,conjugate()
,==
和!=
。除了-
和!=
之外,所有都是抽象的。- real¶
抽象。檢索此數字的實部。
- imag¶
抽象。檢索此數字的虛部。
- abstractmethod conjugate()¶
抽象。返回複共軛。例如,
(1+3j).conjugate() == (1-3j)
。
- class numbers.Real¶
在
Complex
的基礎上,Real
添加了對實數進行操作的運算。簡而言之,這些運算包括:轉換為
float
,math.trunc()
,round()
,math.floor()
,math.ceil()
,divmod()
,//
,%
,<
,<=
,>
和>=
。Real 還為
complex()
、real
、imag
和conjugate()
提供了預設實現。
- class numbers.Rational¶
繼承自
Real
並添加了numerator
和denominator
屬性。它還為float()
提供了預設實現。numerator
和denominator
的值應為Integral
的例項,且應為最簡分數形式,並保持denominator
為正。- numerator¶
抽象。此有理數的分子。
- denominator¶
抽象。此有理數的分母。
型別實現者的注意事項¶
實現者應注意使相等的數字相等,並將其雜湊到相同的值。如果存在實數的兩個不同擴充套件,這可能很微妙。例如,fractions.Fraction
按如下方式實現 hash()
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))
新增更多數值抽象基類¶
當然,數字可能還有更多的抽象基類 (ABC),如果這個層次結構排除了新增這些類的可能性,那它將是一個糟糕的層次結構。你可以在 Complex
和 Real
之間新增 MyFoo
,方法是
class MyFoo(Complex): ...
MyFoo.register(Real)
實現算術運算¶
我們希望實現算術運算,以便混合模式運算要麼呼叫其作者瞭解兩個引數型別的實現,要麼將兩者都轉換為最接近的內建型別並在那裡執行操作。對於 Integral
的子型別,這意味著 __add__()
和 __radd__()
應該定義為
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
對於 Complex
子類上的混合型別操作,有 5 種不同的情況。我將所有不提及 MyIntegral
和 OtherTypeIKnowAbout
的上述程式碼稱為“樣板程式碼”。a
將是 A
的一個例項,A
是 Complex
的子型別(a : A <: Complex
),而 b : B <: Complex
。我將考慮 a + b
。
如果
A
定義了一個接受b
的__add__()
,一切正常。如果
A
回退到樣板程式碼,並且它要從__add__()
返回一個值,我們將錯過B
定義了一個更智慧的__radd__()
的可能性,所以樣板程式碼應該從__add__()
返回NotImplemented
。(或者A
可能根本不實現__add__()
。)然後
B
的__radd__()
有機會執行。如果它接受a
,一切正常。如果它回退到樣板程式碼,就沒有更多可能的方法可以嘗試了,所以這就是預設實現應該存在的地方。
如果
B <: A
,Python 會在A.__add__
之前嘗試B.__radd__
。這是可以的,因為它是在瞭解A
的情況下實現的,因此它可以在委託給Complex
之前處理這些例項。
如果 A <: Complex
且 B <: Real
且它們之間沒有任何其他共享知識,那麼適當的共享操作是涉及內建 complex
的操作,並且兩個 __radd__()
都歸結於此,因此 a+b == b+a
。
由於任何給定型別的大多數操作都非常相似,因此定義一個幫助函式來生成任何給定運算子的正向和反向例項可能很有用。例如,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)
# ...