9.1. numbers — 数字抽象基类 — Python 文档
9.1. 数字 — 数字抽象基类
2.6 版中的新功能。
numbers 模块 (PEP 3141) 定义了数字 抽象基类 的层次结构,它逐渐定义了更多的操作。 此模块中定义的任何类型都无法实例化。
- class numbers.Number
- 数字层次结构的根。 如果您只想检查参数 x 是否是数字,而不关心是什么类型,请使用
isinstance(x, Number)
。
9.1.1. 数字塔
- class numbers.Complex
此类型的子类描述复数并包括对内置 复杂 类型起作用的操作。 它们是:转换为 complex 和 bool、real、imag、
+
、-
、*
、/
、abs()、共轭()、==
和.X198X 除了-
和!=
之外的都是抽象的。- real
抽象的。 检索此数字的实部。
- imag
抽象的。 检索此数字的虚部。
- conjugate()
抽象的。 返回复共轭。 例如,
(1+3j).conjugate() == (1-3j)
。
- class numbers.Real
在 Complex 中,Real 添加了对实数起作用的运算。
简而言之,它们是:转换为 float、math.trunc()、round()、math.floor() , math.ceil(), divmod(),
//
,%
,<
,<=
、>
和>=
。
- class numbers.Rational
子类型 Real 并添加 numerator 和 denominator 属性,这应该是最低的术语。 有了这些,它为 float() 提供了一个默认值。
- numerator
抽象的。
- denominator
抽象的。
- class numbers.Integral
- 子类型 Rational 并添加到 int 的转换。 为 float()、numerator 和 denominator 提供默认值。 为
**
和位串操作添加抽象方法:<<
、>>
、&
、^
、|
,~
。
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. 添加更多数字 ABC
当然,数字有更多可能的 ABC,如果它排除了添加这些的可能性,这将是一个糟糕的层次结构。 您可以在 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
将是 A
的实例,它是 Complex (a : A <: Complex
) 和 b : B <: Complex
的子类型。 我会考虑 a + b
:
- 如果
A
定义了一个接受b
的__add__()
,一切都很好。- 如果
A
退回到样板代码,并且它要从__add__()
返回一个值,我们就会错过B
定义一个更智能的 [ X167X],所以样板应该从__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, long, 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)
# ...