numbers ---数字抽象基类

源代码: Lib/numbers.py


这个 numbers 模块 (PEP 3141 )定义数字的层次结构 abstract base classes 逐步定义更多的操作。不能实例化此模块中定义的任何类型。

class numbers.Number

数值层次结构的根。如果你只想检查一个参数 x 是一个数字,不用管是什么类型,用 isinstance(x, Number) .

数字塔

class numbers.Complex

这种类型的子类描述复杂的数字,并包括对内置的 complex 类型。这些是:转换为 complexboolrealimag+, -, *, /, abs(), conjugate(), `` =`,和 != . 所有除外 -!= 是抽象的。

real

摘要。检索此数字的实际组成部分。

imag

摘要。检索此数字的虚部。

abstractmethod conjugate()

摘要。返回复共轭。例如, (1+3j).conjugate() == (1-3j) .

class numbers.Real

ComplexReal 添加对实数有效的操作。

简而言之,这些是:转换为 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()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的可能性,这将是一个糟糕的层次结构。您可以添加 MyFoo 之间 ComplexReal 用:

class MyFoo(Complex): ...
MyFoo.register(Real)

实现算术运算

我们希望实现算术运算,这样混合模式运算要么调用一个实现,该实现的作者知道这两个参数的类型,要么将这两个参数都转换为最近的内置类型并在其中执行运算。对于subtype 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

对于子类的混合类型操作,有5种不同的情况 Complex . 我将引用上面所有不引用的代码 MyIntegralOtherTypeIKnowAbout 作为“样板”。 a 将是 A ,它是 Complex (a : A <: Complexb : B <: Complex . 我会考虑 a + b

  1. 如果 A 定义一个 __add__() 接受 b 一切都很好。

  2. 如果 A 返回到样板代码,它将返回 __add__() 我们会错过 B 定义更智能的 __radd__() ,所以样板文件应该返回 NotImplemented__add__() . (或) A 可能无法实现 __add__() 总而言之)

  3. 然后 B__radd__() 得到一个机会。如果它接受 a 一切都很好。

  4. 如果返回到样板文件,就没有其他可能的方法可以尝试,因此这就是默认实现应该存在的地方。

  5. 如果 B <: A Python尝试 B.__radd__ 之前 A.__add__ .这是可以的,因为它是在 A ,以便它可以在委托给 Complex .

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

# ...