
PEP原文: https://www.python.org/dev/peps/pep-3141
PEP標(biāo)題: PEP 3141 -- A Type Hierarchy for Numbers
PEP作者: Jeffrey Yasskin
創(chuàng)建日期: 2007-04-23
譯者 :豌豆花下貓
來(lái)源:Python貓
PEP翻譯計(jì)劃: https://github.com/chinesehuazhou/peps-cn
花下貓語(yǔ):在python 中,不同類(lèi)型的數(shù)字可以直接做算術(shù)運(yùn)算,并不需要作顯式的類(lèi)型轉(zhuǎn)換。但是,它的“隱式類(lèi)型轉(zhuǎn)換”可能跟其它語(yǔ)言不同,因?yàn)?python 中的數(shù)字是一種特殊的對(duì)象,派生自同一個(gè)抽象基類(lèi)。在上一篇文章 中,我們討論到了 Python 數(shù)字的運(yùn)算,然后我想探究“Python 的數(shù)字對(duì)象到底是什么”的話題,所以就翻譯了這篇 PEP,希望對(duì)你也有所幫助。
概要
本提案定義了一種抽象基類(lèi)(ABC)(PEP 3119)的層次結(jié)構(gòu),用來(lái)表示類(lèi)似數(shù)字(number-like)的類(lèi)。它提出了一個(gè) Number :> Complex :> Real :> Rational :> Integral 的層次結(jié)構(gòu),其中 A :> B 表示“A 是 B 的超類(lèi)”。該層次結(jié)構(gòu)受到了 Scheme 的數(shù)字塔(numeric tower)啟發(fā)。(譯注:數(shù)字--復(fù)數(shù)--實(shí)數(shù)--有理數(shù)--整數(shù))
基本原理
以數(shù)字作為參數(shù)的函數(shù)應(yīng)該能夠判定這些數(shù)字的屬性,并且根據(jù)數(shù)字的類(lèi)型,確定是否以及何時(shí)進(jìn)行重載,即基于參數(shù)的類(lèi)型,函數(shù)應(yīng)該是可重載的。
例如,切片要求其參數(shù)為Integrals,而math模塊中的函數(shù)要求其參數(shù)為Real。
規(guī)范
本 PEP 規(guī)定了一組抽象基類(lèi)(Abstract Base Class),并提出了一個(gè)實(shí)現(xiàn)某些方法的通用策略。它使用了來(lái)自于PEP 3119的術(shù)語(yǔ),但是該層次結(jié)構(gòu)旨在對(duì)特定類(lèi)集的任何系統(tǒng)方法都有意義。
標(biāo)準(zhǔn)庫(kù)中的類(lèi)型檢查應(yīng)該使用這些類(lèi),而不是具體的內(nèi)置類(lèi)型。
數(shù)值類(lèi)
我們從 Number 類(lèi)開(kāi)始,它是人們想象的數(shù)字類(lèi)型的模糊概念。此類(lèi)僅用于重載;它不提供任何操作。
class Number(metaclass=ABCMeta): pass
大多數(shù)復(fù)數(shù)(complex number)的實(shí)現(xiàn)都是可散列的,但是如果你需要依賴(lài)它,則必須明確地檢查:此層次結(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抽象基類(lèi)表示在實(shí)數(shù)軸上的值,并且支持內(nèi)置的float的操作。實(shí)數(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)庫(kù)。然后它將實(shí)現(xiàn)有理數(shù)(Rational)抽象基類(lèi)。
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ù)類(lèi):
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
運(yùn)算及__magic__方法的變更
為了支持從 float 到 int(確切地說(shuō),從 Real 到 Integral)的精度收縮,我們提出了以下新的 __magic__ 方法,可以從相應(yīng)的庫(kù)函數(shù)中調(diào)用。所有這些方法都返回 Intergral 而不是 Real。
在 2.6 版本中,math.floor、math.ceil 和 round 將繼續(xù)返回浮點(diǎn)數(shù)。
float 的 int() 轉(zhuǎn)換等效于 trunc()。一般而言,int() 的轉(zhuǎn)換首先會(huì)嘗試__int__(),如果找不到,再?lài)L試__trunc__()。
complex.__{divmod, mod, floordiv, int, float}__ 也消失了。提供一個(gè)好的錯(cuò)誤消息來(lái)幫助困惑的搬運(yùn)工會(huì)很好,但更重要的是不出現(xiàn)在 help(complex) 中。
給類(lèi)型實(shí)現(xiàn)者的說(shuō)明
實(shí)現(xiàn)者應(yīng)該注意使相等的數(shù)字相等,并將它們散列為相同的值。如果實(shí)數(shù)有兩個(gè)不同的擴(kuò)展,這可能會(huì)變得微妙。例如,一個(gè)復(fù)數(shù)類(lèi)型可以像這樣合理地實(shí)現(xiàn) hash():
def __hash__(self):
return hash(complex(self))
但應(yīng)注意所有超出了內(nèi)置復(fù)數(shù)范圍或精度的值。
添加更多數(shù)字抽象基類(lèi)
當(dāng)然,數(shù)字還可能有更多的抽象基類(lèi),如果排除了添加這些數(shù)字的可能性,這會(huì)是一個(gè)糟糕的等級(jí)體系。你可以使用以下方法在 Complex 和 Real 之間添加MyFoo:
class MyFoo(Complex): ...
MyFoo.register(Real)
實(shí)現(xiàn)算術(shù)運(yùn)算
我們希望實(shí)現(xiàn)算術(shù)運(yùn)算,使得在混合模式的運(yùn)算時(shí),要么調(diào)用者知道如何處理兩種參數(shù)類(lèi)型,要么將兩者都轉(zhuǎn)換為最接近的內(nèi)置類(lèi)型,并以此進(jìn)行操作。
對(duì)于 Integral 的子類(lèi)型,這意味著__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
對(duì) Complex 的子類(lèi)進(jìn)行混合類(lèi)型操作有 5 種不同的情況。我把以上所有未包含 MyIntegral 和 OtherTypeIKnowAbout 的代碼稱(chēng)為“樣板”。
a 是 A 的實(shí)例,它是Complex(a : A <: Complex) 的子類(lèi)型,還有 b : B <: Complex。對(duì)于 a + b,我這么考慮:
如果 A <: Complex 和 B <: Real 沒(méi)有其它關(guān)系,則合適的共享操作是內(nèi)置復(fù)數(shù)的操作,它們的__radd__都在其中,因此 a + b == b + a。(譯注:這幾段沒(méi)看太明白,可能譯得不對(duì))
被拒絕的方案
本 PEP 的初始版本定義了一個(gè)被 Haskell Numeric Prelude 所啟發(fā)的代數(shù)層次結(jié)構(gòu),其中包括 MonoidUnderPlus、AdditiveGroup、Ring 和 Field,并在得到數(shù)字之前,還有其它幾種可能的代數(shù)類(lèi)型。
我們?cè)鞠M@對(duì)使用向量和矩陣的人有用,但 NumPy 社區(qū)確實(shí)對(duì)此并不感興趣,另外我們還遇到了一個(gè)問(wèn)題,即便 x 是 X <: MonoidUnderPlus 的實(shí)例,而且 y 是 Y < : MonoidUnderPlus 的實(shí)例,x + y 可能還是行不通。
然后,我們?yōu)閿?shù)字提供了更多的分支結(jié)構(gòu),包括高斯整數(shù)(Gaussian Integer)和 Z/nZ 之類(lèi)的東西,它們可以是 Complex,但不一定支持“除”之類(lèi)的操作。
社區(qū)認(rèn)為這對(duì) Python 來(lái)說(shuō)太復(fù)雜了,因此我現(xiàn)在縮小了提案的范圍,使其更接近于 Scheme 數(shù)字塔。
十進(jìn)制類(lèi)型
經(jīng)與作者協(xié)商,已決定目前不將 Decimal 類(lèi)型作為數(shù)字塔的一部分。
參考文獻(xiàn)
1、抽象基類(lèi)簡(jiǎn)介:http://www.python.org/dev/peps/pep-3119/
2、可能是 Python 3 的類(lèi)樹(shù)?Bill Janssen 的 Wiki 頁(yè)面:http://wiki.python.org/moin/AbstractBaseClasses
3、NumericPrelude:數(shù)字類(lèi)型類(lèi)的實(shí)驗(yàn)性備選層次結(jié)構(gòu):http://darcs.haskell.org/numericprelude/docs/html/index.html
4、Scheme 數(shù)字塔:https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50
(譯注:在譯完之后,我才發(fā)現(xiàn)“PEP中文翻譯計(jì)劃”已收錄過(guò)一篇譯文,有些地方譯得不盡相同,讀者們可點(diǎn)擊閱讀原文,比對(duì)閱讀。)
致謝
感謝 Neal Norwitz 最初鼓勵(lì)我編寫(xiě)此 PEP,感謝 Travis Oliphant 指出 numpy 社區(qū)并不真正關(guān)心代數(shù)概念,感謝 Alan Isaac 提醒我 Scheme 已經(jīng)做到了,以及感謝 Guido van Rossum 和郵件組里的其他人幫忙完善了這套概念。
數(shù)據(jù)分析咨詢(xún)請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
LSTM 模型輸入長(zhǎng)度選擇技巧:提升序列建模效能的關(guān)鍵? 在循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)家族中,長(zhǎng)短期記憶網(wǎng)絡(luò)(LSTM)憑借其解決長(zhǎng)序列 ...
2025-07-11CDA 數(shù)據(jù)分析師報(bào)考條件詳解與準(zhǔn)備指南? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代浪潮下,CDA 數(shù)據(jù)分析師認(rèn)證愈發(fā)受到矚目,成為眾多有志投身數(shù) ...
2025-07-11數(shù)據(jù)透視表中兩列相乘合計(jì)的實(shí)用指南? 在數(shù)據(jù)分析的日常工作中,數(shù)據(jù)透視表憑借其強(qiáng)大的數(shù)據(jù)匯總和分析功能,成為了 Excel 用戶(hù) ...
2025-07-11尊敬的考生: 您好! 我們誠(chéng)摯通知您,CDA Level I和 Level II考試大綱將于 2025年7月25日 實(shí)施重大更新。 此次更新旨在確保認(rèn) ...
2025-07-10BI 大數(shù)據(jù)分析師:連接數(shù)據(jù)與業(yè)務(wù)的價(jià)值轉(zhuǎn)化者? ? 在大數(shù)據(jù)與商業(yè)智能(Business Intelligence,簡(jiǎn)稱(chēng) BI)深度融合的時(shí)代,BI ...
2025-07-10SQL 在預(yù)測(cè)分析中的應(yīng)用:從數(shù)據(jù)查詢(xún)到趨勢(shì)預(yù)判? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代,預(yù)測(cè)分析作為挖掘數(shù)據(jù)潛在價(jià)值的核心手段,正被廣泛 ...
2025-07-10數(shù)據(jù)查詢(xún)結(jié)束后:分析師的收尾工作與價(jià)值深化? ? 在數(shù)據(jù)分析的全流程中,“query end”(查詢(xún)結(jié)束)并非工作的終點(diǎn),而是將數(shù) ...
2025-07-10CDA 數(shù)據(jù)分析師考試:從報(bào)考到取證的全攻略? 在數(shù)字經(jīng)濟(jì)蓬勃發(fā)展的今天,數(shù)據(jù)分析師已成為各行業(yè)爭(zhēng)搶的核心人才,而 CDA(Certi ...
2025-07-09【CDA干貨】單樣本趨勢(shì)性檢驗(yàn):捕捉數(shù)據(jù)背后的時(shí)間軌跡? 在數(shù)據(jù)分析的版圖中,單樣本趨勢(shì)性檢驗(yàn)如同一位耐心的偵探,專(zhuān)注于從單 ...
2025-07-09year_month數(shù)據(jù)類(lèi)型:時(shí)間維度的精準(zhǔn)切片? ? 在數(shù)據(jù)的世界里,時(shí)間是最不可或缺的維度之一,而year_month數(shù)據(jù)類(lèi)型就像一把精準(zhǔn) ...
2025-07-09CDA 備考干貨:Python 在數(shù)據(jù)分析中的核心應(yīng)用與實(shí)戰(zhàn)技巧? ? 在 CDA 數(shù)據(jù)分析師認(rèn)證考試中,Python 作為數(shù)據(jù)處理與分析的核心 ...
2025-07-08SPSS 中的 Mann-Kendall 檢驗(yàn):數(shù)據(jù)趨勢(shì)與突變分析的有力工具? ? ? 在數(shù)據(jù)分析的廣袤領(lǐng)域中,準(zhǔn)確捕捉數(shù)據(jù)的趨勢(shì)變化以及識(shí)別 ...
2025-07-08備戰(zhàn) CDA 數(shù)據(jù)分析師考試:需要多久?如何規(guī)劃? CDA(Certified Data Analyst)數(shù)據(jù)分析師認(rèn)證作為國(guó)內(nèi)權(quán)威的數(shù)據(jù)分析能力認(rèn)證 ...
2025-07-08LSTM 輸出不確定的成因、影響與應(yīng)對(duì)策略? 長(zhǎng)短期記憶網(wǎng)絡(luò)(LSTM)作為循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)的一種變體,憑借獨(dú)特的門(mén)控機(jī)制,在 ...
2025-07-07統(tǒng)計(jì)學(xué)方法在市場(chǎng)調(diào)研數(shù)據(jù)中的深度應(yīng)用? 市場(chǎng)調(diào)研是企業(yè)洞察市場(chǎng)動(dòng)態(tài)、了解消費(fèi)者需求的重要途徑,而統(tǒng)計(jì)學(xué)方法則是市場(chǎng)調(diào)研數(shù) ...
2025-07-07CDA數(shù)據(jù)分析師證書(shū)考試全攻略? 在數(shù)字化浪潮席卷全球的當(dāng)下,數(shù)據(jù)已成為企業(yè)決策、行業(yè)發(fā)展的核心驅(qū)動(dòng)力,數(shù)據(jù)分析師也因此成為 ...
2025-07-07剖析 CDA 數(shù)據(jù)分析師考試題型:解鎖高效備考與答題策略? CDA(Certified Data Analyst)數(shù)據(jù)分析師考試作為衡量數(shù)據(jù)專(zhuān)業(yè)能力的 ...
2025-07-04SQL Server 字符串截取轉(zhuǎn)日期:解鎖數(shù)據(jù)處理的關(guān)鍵技能? 在數(shù)據(jù)處理與分析工作中,數(shù)據(jù)格式的規(guī)范性是保證后續(xù)分析準(zhǔn)確性的基礎(chǔ) ...
2025-07-04CDA 數(shù)據(jù)分析師視角:從數(shù)據(jù)迷霧中探尋商業(yè)真相? 在數(shù)字化浪潮席卷全球的今天,數(shù)據(jù)已成為企業(yè)決策的核心驅(qū)動(dòng)力,CDA(Certifie ...
2025-07-04CDA 數(shù)據(jù)分析師:開(kāi)啟數(shù)據(jù)職業(yè)發(fā)展新征程? ? 在數(shù)據(jù)成為核心生產(chǎn)要素的今天,數(shù)據(jù)分析師的職業(yè)價(jià)值愈發(fā)凸顯。CDA(Certified D ...
2025-07-03