您好,登錄后才能下訂單哦!
本篇文章為大家展示了python中的數(shù)字深入淺出,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
概要
本提案定義了一種抽象基類(ABC)(PEP 3119)的層次結(jié)構(gòu),用來表示類似數(shù)字(number-like)的類。它提出了一個 Number :> Complex :> Real :> Rational :> Integral 的層次結(jié)構(gòu),其中 A :> B 表示“A 是 B 的超類”。該層次結(jié)構(gòu)受到了 Scheme 的數(shù)字塔(numeric tower)啟發(fā)。(譯注:數(shù)字--復(fù)數(shù)--實數(shù)--有理數(shù)--整數(shù))
基本原理
以數(shù)字作為參數(shù)的函數(shù)應(yīng)該能夠判定這些數(shù)字的屬性,并且根據(jù)數(shù)字的類型,確定是否以及何時進(jìn)行重載,即基于參數(shù)的類型,函數(shù)應(yīng)該是可重載的。
例如,切片要求其參數(shù)為Integrals,而math模塊中的函數(shù)要求其參數(shù)為Real。
規(guī)范
本 PEP 規(guī)定了一組抽象基類(Abstract Base Class),并提出了一個實現(xiàn)某些方法的通用策略。它使用了來自于PEP 3119的術(shù)語,但是該層次結(jié)構(gòu)旨在對特定類集的任何系統(tǒng)方法都有意義。
標(biāo)準(zhǔn)庫中的類型檢查應(yīng)該使用這些類,而不是具體的內(nèi)置類型。
數(shù)值類
我們從 Number 類開始,它是人們想象的數(shù)字類型的模糊概念。此類僅用于重載;它不提供任何操作。
class Number(metaclass=ABCMeta): pass
大多數(shù)復(fù)數(shù)(complex number)的實現(xiàn)都是可散列的,但是如果你需要依賴它,則必須明確地檢查:此層次結(jié)構(gòu)支持可變的數(shù)。
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抽象基類表示在實數(shù)軸上的值,并且支持內(nèi)置的float的操作。實數(shù)(Real number)是完全有序的,除了 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
我們應(yīng)該整理 Demo/classes/Rat.py,并把它提升為 Rational.py 加入標(biāo)準(zhǔn)庫。然后它將實現(xiàn)有理數(shù)(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
最后是整數(shù)類:
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__ 方法,可以從相應(yīng)的庫函數(shù)中調(diào)用。所有這些方法都返回 Intergral 而不是 Real。
__trunc__(self):在新的內(nèi)置 trunc(x) 里調(diào)用,它返回從 0 到 x 之間的最接近 x 的 Integral。
__floor__(self):在 math.floor(x) 里調(diào)用,返回最大的 Integral <= x。
__ceil__(self):在 math.ceil(x) 里調(diào)用,返回最小的 Integral > = x。
__round__(self):在 round(x) 里調(diào)用,返回最接近 x 的 Integral ,根據(jù)選定的類型作四舍五入。浮點數(shù)將從 3.0 版本起改為向偶數(shù)端四舍五入。(譯注:round(2.5) 等于 2,round(3.5) 等于 4)。它還有一個帶兩參數(shù)的版本__round__(self, ndigits),被 round(x, ndigits) 調(diào)用,但返回的是一個 Real。
在 2.6 版本中,math.floor、math.ceil 和 round 將繼續(xù)返回浮點數(shù)。
float 的 int() 轉(zhuǎn)換等效于 trunc()。一般而言,int() 的轉(zhuǎn)換首先會嘗試__int__(),如果找不到,再嘗試__trunc__()。
complex.__{divmod, mod, floordiv, int, float}__ 也消失了。提供一個好的錯誤消息來幫助困惑的搬運工會很好,但更重要的是不出現(xiàn)在 help(complex) 中。
給類型實現(xiàn)者的說明
實現(xiàn)者應(yīng)該注意使相等的數(shù)字相等,并將它們散列為相同的值。如果實數(shù)有兩個不同的擴展,這可能會變得微妙。例如,一個復(fù)數(shù)類型可以像這樣合理地實現(xiàn) hash():
def __hash__(self): return hash(complex(self))
但應(yīng)注意所有超出了內(nèi)置復(fù)數(shù)范圍或精度的值。
添加更多數(shù)字抽象基類
當(dāng)然,數(shù)字還可能有更多的抽象基類,如果排除了添加這些數(shù)字的可能性,這會是一個糟糕的等級體系。你可以使用以下方法在 Complex 和 Real 之間添加MyFoo:
class MyFoo(Complex): ... MyFoo.register(Real)
實現(xiàn)算術(shù)運算
我們希望實現(xiàn)算術(shù)運算,使得在混合模式的運算時,要么調(diào)用者知道如何處理兩種參數(shù)類型,要么將兩者都轉(zhuǎn)換為最接近的內(nèi)置類型,并以此進(jìn)行操作。
對于 Integral 的子類型,這意味著__add__和__radd__應(yīng)該被定義為:
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 的子類進(jìn)行混合類型操作有 5 種不同的情況。我把以上所有未包含 MyIntegral 和 OtherTypeIKnowAbout 的代碼稱為“樣板”。
a 是 A 的實例,它是Complex(a : A <: Complex) 的子類型,還有 b : B <: Complex。對于 a + b,我這么考慮:
如果 A 定義了接受 b 的__add__,那么沒問題。
如果 A 走到了樣板代碼分支(譯注:else 分支),還從__add__返回一個值的話,那么我們就錯過了為 B 定義一個更智能的__radd__的可能性,因此樣板應(yīng)該從__add__返回 NotImplemented。(或者 A 可以不實現(xiàn)__add__)
然后 B 的__radd__的機會來了。如果它接受 a,那么沒問題。
如果它走到樣板分支上,就沒有辦法了,因此需要有默認(rèn)的實現(xiàn)。
如果 B <: A,則 Python 會在 A.__ add__之前嘗試 B.__ radd__。這也可以,因為它是基于 A 而實現(xiàn)的,因此可以在委派給 Complex 之前處理這些實例。
如果 A <: Complex 和 B <: Real 沒有其它關(guān)系,則合適的共享操作是內(nèi)置復(fù)數(shù)的操作,它們的__radd__都在其中,因此 a + b == b + a。(譯注:這幾段沒看太明白,可能譯得不對)
被拒絕的方案
本 PEP 的初始版本定義了一個被 Haskell Numeric Prelude 所啟發(fā)的代數(shù)層次結(jié)構(gòu),其中包括 MonoidUnderPlus、AdditiveGroup、Ring 和 Field,并在得到數(shù)字之前,還有其它幾種可能的代數(shù)類型。
我們原本希望這對使用向量和矩陣的人有用,但 NumPy 社區(qū)確實對此并不感興趣,另外我們還遇到了一個問題,即便 x 是 X <: MonoidUnderPlus 的實例,而且 y 是 Y < : MonoidUnderPlus 的實例,x + y 可能還是行不通。
然后,我們?yōu)閿?shù)字提供了更多的分支結(jié)構(gòu),包括高斯整數(shù)(Gaussian Integer)和 Z/nZ 之類的東西,它們可以是 Complex,但不一定支持“除”之類的操作。
社區(qū)認(rèn)為這對 Python 來說太復(fù)雜了,因此我現(xiàn)在縮小了提案的范圍,使其更接近于 Scheme 數(shù)字塔。
十進(jìn)制類型
經(jīng)與作者協(xié)商,已決定目前不將 Decimal 類型作為數(shù)字塔的一部分。
上述內(nèi)容就是python中的數(shù)字深入淺出,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。