numbers — 数字抽象基类 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/numbers
跳转至:导航、​搜索

numbers — 数字抽象基类

源代码: :source:`Lib/numbers.py`



numbers 模块 (PEP 3141) 定义了数字 抽象基类 的层次结构,它逐渐定义了更多的操作。 此模块中定义的任何类型都无法实例化。

class numbers.Number
数字层次结构的根。 如果您只想检查参数 x 是否是数字,而不关心是什么类型,请使用 isinstance(x, Number)

数字塔

class numbers.Complex

此类型的子类描述复数并包括对内置 复杂 类型起作用的操作。 它们是:转换为 complexboolrealimag+-*/abs()conjugate()==!=。 除了 -!= 之外的都是抽象的。

real

抽象的。 检索此数字的实部。

imag

抽象的。 检索此数字的虚部。

class numbers.Real

Complex 中,Real 添加了对实数起作用的运算。

简而言之,它们是:转换为 floatmath.trunc()round()math.floor() , math.ceil(), divmod(), //, %, <, <=>>=

Real 还为 complex()realimagconjugate() 提供默认值。

class numbers.Rational

子类型 Real 并添加 numeratordenominator 属性,这应该是最低的术语。 有了这些,它为 float() 提供了一个默认值。

numerator

抽象的。

denominator

抽象的。

class numbers.Integral
子类型 Rational 并添加到 int 的转换。 为 float()numeratordenominator 提供默认值。 为 ** 和位串操作添加抽象方法:<<>>&^| , ~


类型实现者注意事项

实现者应该小心使相等的数字相等并将它们散列到相同的值。 如果实数有两个不同的扩展,这可能很微妙。 例如, 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,如果它排除了添加这些的可能性,这将是一个糟糕的层次结构。 您可以在 ComplexReal 之间添加 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 种不同的情况。 我将上述所有没有引用 MyIntegralOtherTypeIKnowAbout 的代码称为“样板”。 a 将是 A 的实例,它是 Complex (a : A <: Complex) 和 b : B <: Complex 的子类型。 我会考虑 a + b

  1. 如果 A 定义了一个接受 b__add__(),一切都很好。
  2. 如果 A 退回到样板代码,并且它要从 __add__() 返回一个值,我们就会错过 B 定义一个更智能的 [ X167X],所以样板应该从 __add__() 返回 NotImplemented。 (或者 A 可能根本无法实现 __add__()。)
  3. 那么B__radd__()就有机会了。 如果它接受 a,一切都很好。
  4. 如果它回退到样板,就没有更多可能的方法可以尝试,所以这是默认实现应该存在的地方。
  5. 如果是 B <: A,Python 会在 A.__add__ 之前尝试 B.__radd__。 这是可以的,因为它是利用 A 的知识实现的,因此它可以在委托给 Complex 之前处理这些实例。


如果 A <: ComplexB <: 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)

# ...