numbers-数字抽象基类详解 – (1)Python语言的数学和数学模块(必读进阶学习教程)(参考资料)
数字模块定义了数字抽象基类的层次结构,这些基类逐渐定义了更多操作。 此模块中定义的任何类型都不能被实例化。
- 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
- To
Complex
,Real
添加了对实数进行处理的操作。简而言之,它们是:转换为 float、math.trunc()、round()、math.floor()、math.ceil()、divmod()、//、%、<、<=、> 和 >=。
真正还提供了默认值
complex()
,real
,imag
,和conjugate()
。
- class
numbers.
Rational
- 子类型 Real 并添加分子和分母属性,这些属性应该是最低的。 有了这些,它为 float() 提供了默认值。
numerator
- 抽象。
denominator
- 抽象。
- class
numbers.
Integral
- 子类型 Rational 并添加到 int 的转换。 为 float()、分子和分母提供默认值。 为 ** 和位串操作添加抽象方法:<<、>>、&、^、|、~。
类使用的注意事项
实现者应该小心使相等的数字相等并将它们散列为相同的值。 如果实数有两个不同的扩展,这可能是微妙的。 例如,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,如果它排除了添加这些的可能性,那么这将是一个糟糕的层次结构。您可以添加MyFoo
之间Complex
,并 Real
搭配:
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 不共享任何其他知识,则适当的共享操作是涉及内置复数的操作,并且两个 __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, 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)
# ...