知行编程网知行编程网  2022-12-10 08:30 知行编程网 隐藏边栏  8 
文章评分 0 次,平均分 0.0
导语: 本文主要介绍了关于认识python中的数字的相关知识,希望可以帮到处于编程学习途中的小伙伴

在python中识别数字



概要

该提案定义了抽象基类 (ABC) (PEP 3119) 的层次结构,用于表示类似数字的类。它提出了 Number :> Complex :> Real :> Rational :> Integral 的层次结构,其中 A :> B 表示“A 是 B 的超类”。层次结构的灵感来自 Scheme 的数字塔。 (译注:数-复数-实数-有理数-整数)



基本原理

以数字为参数的函数应该能够确定这些数字的属性,并根据数字的类型确定是否以及何时重载,即根据参数的类型,函数应该是可重载的。

例如,切片要求其参数为 Integrals,而 math 模块中的函数要求其参数为 Real。



规范

该 PEP 指定了一组抽象基类,并提出了实现某些方法的通用策略。它使用 PEP 3119 中的术语,但层次结构旨在让任何系统方法对一组特定的类有意义。

标准库中的类型检查应该使用这些类,而不是具体的内置类型。



数值类

我们从 Number 类开始,它是 1 号想象的类型的模糊概念。此类仅用于重载;它不提供任何操作。

class Number(metaclass=ABCMeta): pass

大多数复数的实现都是可散列的,但如果你需要依赖于此,则必须明确检查:此层次结构支持可变数字。

class Complex(Number):
    """Complex defines the operations that work on the builtin complex type.
    In short, those are: conversion to complex, bool(), .real, .imag,
    +, -, *, /, **, abs(), .conjugate(), ==, and !=.
    If it is given heterogenous arguments, and doesn't have special
    knowledge about them, it should fall back to the builtin complex
    type as described below.
    """
    @abstractmethod
    def __complex__(self):
        """Return a builtin complex instance."""
    def __bool__(self):
        """True if self != 0."""
        return self != 0
    @abstractproperty
    def real(self):
        """Retrieve the real component of this number.
        This should subclass Real.
        """
        raise NotImplementedError
    @abstractproperty
    def imag(self):
        """Retrieve the real component of this number.
        This should subclass Real.
        """
        raise NotImplementedError
    @abstractmethod
    def __add__(self, other):
        raise NotImplementedError
    @abstractmethod
    def __radd__(self, other):
        raise NotImplementedError
    @abstractmethod
    def __neg__(self):
        raise NotImplementedError
    def __pos__(self):
        """Coerces self to whatever class defines the method."""
        raise NotImplementedError
    def __sub__(self, other):
        return self + -other
    def __rsub__(self, other):
        return -self + other
    @abstractmethod
    def __mul__(self, other):
        raise NotImplementedError
    @abstractmethod
    def __rmul__(self, other):
        raise NotImplementedError
    @abstractmethod
    def __div__(self, other):
        """a/b; should promote to float or complex when necessary."""
        raise NotImplementedError
    @abstractmethod
    def __rdiv__(self, other):
        raise NotImplementedError
    @abstractmethod
    def __pow__(self, exponent):
        """a**b; should promote to float or complex when necessary."""
        raise NotImplementedError
    @abstractmethod
    def __rpow__(self, base):
        raise NotImplementedError
    @abstractmethod
    def __abs__(self):
        """Returns the Real distance from 0."""
        raise NotImplementedError
    @abstractmethod
    def conjugate(self):
        """(x+y*i).conjugate() returns (x-y*i)."""
        raise NotImplementedError
    @abstractmethod
    def __eq__(self, other):
        raise NotImplementedError
    # __ne__ is inherited from object and negates whatever __eq__ does.

Real抽象基类表示实轴上的值,支持内置的浮点运算。实数是完全有序的,除了 NaN(在本 PEP 中基本上被忽略)。

class Real(Complex):
    """To Complex, Real adds the operations that work on real numbers.
    In short, those are: conversion to float, trunc(), math.floor(),
    math.ceil(), round(), divmod(), //, %, <, <=, >, and >=.
    Real also provides defaults for some of the derived operations.
    """
    # XXX What to do about the __int__ implementation that's
    # currently present on float?  Get rid of it?
    @abstractmethod
    def __float__(self):
        """Any Real can be converted to a native float object."""
        raise NotImplementedError
    @abstractmethod
    def __trunc__(self):
        """Truncates self to an Integral.
        Returns an Integral i such that:
          * i>=0 iff self>0;
          * abs(i) <= abs(self);
          * for any Integral j satisfying the first two conditions,
            abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
        i.e. "truncate towards 0".
        """
        raise NotImplementedError
    @abstractmethod
    def __floor__(self):
        """Finds the greatest Integral <= self."""
        raise NotImplementedError
    @abstractmethod
    def __ceil__(self):
        """Finds the least Integral >= self."""
        raise NotImplementedError
    @abstractmethod
    def __round__(self, ndigits:Integral=None):
        """Rounds self to ndigits decimal places, defaulting to 0.
        If ndigits is omitted or None, returns an Integral,
        otherwise returns a Real, preferably of the same type as
        self. Types may choose which direction to round half. For
        example, float rounds half toward even.
        """
        raise NotImplementedError
    def __divmod__(self, other):
        """The pair (self // other, self % other).
        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (self // other, self % other)
    def __rdivmod__(self, other):
        """The pair (self // other, self % other).
        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (other // self, other % self)
    @abstractmethod
    def __floordiv__(self, other):
        """The floor() of self/other. Integral."""
        raise NotImplementedError
    @abstractmethod
    def __rfloordiv__(self, other):
        """The floor() of other/self."""
        raise NotImplementedError
    @abstractmethod
    def __mod__(self, other):
        """self % other
        See
        https://mail.python.org/pipermail/python-3000/2006-May/001735.html
        and consider using "self/other - trunc(self/other)"
        instead if you're worried about round-off errors.
        """
        raise NotImplementedError
    @abstractmethod
    def __rmod__(self, other):
        """other % self"""
        raise NotImplementedError
    @abstractmethod
    def __lt__(self, other):
        """< on Reals defines a total ordering, except perhaps for NaN."""
        raise NotImplementedError
    @abstractmethod
    def __le__(self, other):
        raise NotImplementedError
    # __gt__ and __ge__ are automatically done by reversing the arguments.
    # (But __le__ is not computed as the opposite of __gt__!)
    # Concrete implementations of Complex abstract methods.
    # Subclasses may override these, but don't have to.
    def __complex__(self):
        return complex(float(self))
    @property
    def real(self):
        return +self
    @property
    def imag(self):
        return 0
    def conjugate(self):
        """Conjugate is a no-op for Reals."""
        return +self

整理一下Demo/classes/Rat.py,将其提升为Rational.py,进入标准库。然后它将实现 Rational 抽象基类。

class Rational(Real, Exact):
    """.numerator and .denominator should be in lowest terms."""
    @abstractproperty
    def numerator(self):
        raise NotImplementedError
    @abstractproperty
    def denominator(self):
        raise NotImplementedError
    # Concrete implementation of Real's conversion to float.
    # (This invokes Integer.__div__().)
    def __float__(self):
        return self.numerator / self.denominator

最后是整数类:

class Integral(Rational):
    """Integral adds a conversion to int and the bit-string operations."""
    @abstractmethod
    def __int__(self):
        raise NotImplementedError
    def __index__(self):
        """__index__() exists because float has __int__()."""
        return int(self)
    def __lshift__(self, other):
        return int(self) << int(other)
    def __rlshift__(self, other):
        return int(other) << int(self)
    def __rshift__(self, other):
        return int(self) >> int(other)
    def __rrshift__(self, other):
        return int(other) >> int(self)
    def __and__(self, other):
        return int(self) & int(other)
    def __rand__(self, other):
        return int(other) & int(self)
    def __xor__(self, other):
        return int(self) ^ int(other)
    def __rxor__(self, other):
        return int(other) ^ int(self)
    def __or__(self, other):
        return int(self) | int(other)
    def __ror__(self, other):
        return int(other) | int(self)
    def __invert__(self):
        return ~int(self)
    # Concrete implementations of Rational and Real abstract methods.
    def __float__(self):
        """float(self) == float(int(self))"""
        return float(int(self))
    @property
    def numerator(self):
        """Integers are their own numerators."""
        return +self
    @property
    def denominator(self):
        """Integers have a denominator of 1."""
        return 1



运算及__magic__方法的变更

为了支持从 float 到 int 的精度收缩(实际上,从 Real 到 Integral),我们提出了以下新的 __magic__ 方法,可以从相应的库函数中调用这些方法。所有这些方法都返回 Integral 而不是 Real。

__trunc__(self):在新内置的trunc(x)中调用,返回从0到x最接近x的Integral。

__floor__(self):在 math.floor(x) 里调用,返回 Integral <= x。

__ceil__(self):在 math.ceil(x) 里调用,返回最小的 Integral > = x。

__round__(self):在round(x)中调用,返回最接近x的Integral,根据选择的类型四舍五入。从 3.0 版本开始,浮点数将向偶数端四舍五入。 (译注:round(2.5)等于2,round(3.5)等于4)。它还有一个双参数版本 __round__(self, ndigits),由 round(x, ndigits) 调用,但返回一个实数。

在 2.6 版本中,math.floor、math.ceil 和 round 将继续返回浮点数。

int() 到 float 的转换等同于 trunc()。通常,转换为 int() 将首先尝试 __int__(),如果找不到,则尝试 __trunc__()。

complex.__{divmod, mod, floordiv, int, float}__ 也不见了。提供一个好的错误消息来帮助困惑的码头工人会很好,但更重要的是不要出现在 help(complex) 中。



给类型实现者的说明

实现者应该注意使相等的数字相等并将它们散列为相同的值。如果实数有两个不同的扩展名,这可能会变得微妙。例如,复杂类型可以像这样合理地实现 hash() :

def __hash__(self):
    return hash(complex(self))

但应注意所有超出内置复数范围或精度的值。



添加更多数字抽象基类

当然,数字可以有更多的抽象基类,排除添加这些数字的可能性将是一个糟糕的层次结构。你可以使用以下方法在 Complex 和 Real 之间添加 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 种不同的情况。我将上述所有不包括 MyIntegral 和 OtherTypeIKnowAbout 的代码称为“样板”。

a 是 A 的实例,它是Complex(a : A <: Complex) 的子类型,还有 b : B <: Complex。对于 a + b,我这么考虑:

  • 如果 A 定义了接受 b 的__add__,那么没问题。

  • 如果A走到样板代码分支(译注:else分支),也从__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。 (译注:这几段我没看懂,可能翻译有误)



被拒绝的方案

本 PEP 的初始版本定义了一个受 Haskell Numeric Prelude 启发的代数层次结构,其中包括 MonoidUnderPlus、AdditiveGroup、Ring 和 Field,以及其他几种在获取数字之前可能的代数类型。

我们曾希望这对使用向量和矩阵的人有用,但 NumPy 社区真的对此不感兴趣,我们还遇到了一个问题,其中 x 是 X <: MonoidUnderPlus 的一个实例,y 是一个实例Y <: MonoidUnderPlus , x + y 可能仍然不起作用。

然后我们有更多的数字分支结构,包括像高斯整数和 Z/nZ 这样的东西,它们可以是 Complex 但不一定支持像“除”这样的操作。

社区认为这对于 Python 来说太复杂了,所以我现在缩小了提议的范围,使其更接近 Scheme 图塔。



十进制类型

与作者协商后,决定此时不将 Decimal 类型作为数字塔的一部分。


更多相关免费学习推荐:

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写
扫一扫二维码分享