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¶
當然,還有更多可能的數字 ABC,如果它排除了新增這些 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
的例項,它是 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)
# ...