9.1. numbers
- 数字抽象基类¶
源代码: Lib/numbers.py
numbers
模块( PEP 3141)定义了逐渐定义更多操作的数字abstract base classes的层次结构。本模块中定义的任何类型,都不能被实例化。
- class
numbers.
Number
¶ 数字层次结构的根。如果只想检查参数x是否为数字,而不考虑什么类型,请使用
isinstance(x, Number)
。
9.1.1.The numeric tower¶
- class
numbers.
Complex
¶ 此类型的子类描述复数,并包括对内建
complex
类型工作的操作。These are: conversions tocomplex
andbool
,real
,imag
,+
,-
,*
,/
,abs()
,conjugate()
,==
, and!=
. 除-
和!=
之外的都是抽象的。real
¶抽象。检索此数的实数分量。
imag
¶抽象。检索此数的虚数分量。
- abstractmethod
conjugate
()¶ 抽象。返回共轭复数。例如,
(1 + 3j).conjugate() == (1-3j)
。
- class
numbers.
Real
¶ In short, those are: a conversion to
float
,math.trunc()
,round()
,math.floor()
,math.ceil()
,divmod()
,//
,%
,<
,<=
,>
, and>=
.Real还为
complex()
,real
,imag
和conjugate()
提供默认值。
9.1.2.类型实现的注意事项¶
执行者要小心使相等的数字相等和散列他们为相同的值。这可能是实数的微妙的如果有两个不同的扩展。例如,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))
9.1.2.1.添加更多数字ABCS ¶
当然,有数字,更有可能基本要领,如果它排除了那些增加的可能性,这将是糟糕的层次结构。您可以在Complex
和Real
之间添加MyFoo
:
class MyFoo(Complex): ...
MyFoo.register(Real)
9.1.2.2.实现算术运算¶
我们想要实现的算术运算,以便混合模式操作调用的作者知道这两个参数的类型的实现或都转换为最近内建类型和那里操作。对于子类型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
will be an instance of A
, which is a subtype of Complex
(a : A <: Complex
), and b : B <: Complex
. 我会考虑a + b
:
- If
A
defines an__add__()
which acceptsb
, all is well.- If
A
falls back to the boilerplate code, and it were to return a value from__add__()
, we’d miss the possibility thatB
defines a more intelligent__radd__()
, so the boilerplate should returnNotImplemented
from__add__()
. (OrA
may not implement__add__()
at all.)- Then
B
‘s__radd__()
gets a chance. If it acceptsa
, all is well.- If it falls back to the boilerplate, there are no more possible methods to try, so this is where the default implementation should live.
- If
B <: A
, Python triesB.__radd__
beforeA.__add__
. This is ok, because it was implemented with knowledge ofA
, so it can handle those instances before delegating toComplex
.
If A <: Complex
and B <: Real
without sharing any other knowledge, then the appropriate shared operation is the one involving the built in complex
, and both __radd__()
s land there, so a+b == b+a
.
由于大多数任何给定类型操作会很相似,因此,它能定义可生成任何给定操作正反向实例的 helper 函数。例如,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, 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)
# ...