Python程式設計基礎:數值型別的魔法方法

關注公眾號:

用Python學機器學習

,獲取更多更新。

上一篇文章

Python程式設計基礎:基本資料型別之整型資料

,我們介紹了Python中的數值型別,我們提到數值型別支援的操作,即各種數學運算背後都對應一個魔法方法,實際上Python中所有的運算子都對應一個魔法方法,這一篇文章我們就來看一下數值型別中常用的魔法方法。

魔法方法概述

Python中,內建了一批以雙下劃線開頭,雙下劃線結尾的方法,稱為魔法方法(這一點需要與私有方法相區分,私有方法是以雙下劃線開頭)。例如,整數型別的魔法方法可以使用如下程式碼來檢視:

>>>int。__dict__。keys()dict_keys([‘__repr__’, ‘__hash__’, ‘__getattribute__’, ‘__lt__’, ‘__le__’, ‘__eq__’, ‘__ne__’, ‘__gt__’, ‘__ge__’, ‘__add__’, ‘__radd__’, ‘__sub__’, ‘__rsub__’, ‘__mul__’, ‘__rmul__’, ‘__mod__’, ‘__rmod__’, ‘__divmod__’, ‘__rdivmod__’, ‘__pow__’, ‘__rpow__’, ‘__neg__’, ‘__pos__’, ‘__abs__’, ‘__bool__’, ‘__invert__’, ‘__lshift__’, ‘__rlshift__’, ‘__rshift__’, ‘__rrshift__’, ‘__and__’, ‘__rand__’, ‘__xor__’, ‘__rxor__’, ‘__or__’, ‘__ror__’, ‘__int__’, ‘__float__’, ‘__floordiv__’, ‘__rfloordiv__’, ‘__truediv__’, ‘__rtruediv__’, ‘__index__’, ‘__new__’, ‘conjugate’, ‘bit_length’, ‘to_bytes’, ‘from_bytes’, ‘as_integer_ratio’, ‘__trunc__’, ‘__floor__’, ‘__ceil__’, ‘__round__’, ‘__getnewargs__’, ‘__format__’, ‘__sizeof__’, ‘real’, ‘imag’, ‘numerator’, ‘denominator’, ‘__doc__’])

可以看到這些魔法方法有很多,有一些是Python內建類物件都有的魔法方法,如__new__,有一些則是數值型別具有的魔法方法。這篇文章我們介紹與數學運算相關的魔法方法,包括單目運算方法、比較運算方法、算數運算方法、反射算數運算方法,其他魔法方法我們會在後面的文章中穿插進行介紹。

魔法方法概述

單目運算方法包括:

單目運算方法:

。主要實現資料的取正、取負、取絕對值、資料截斷等等。

單目運算方法:

方法主要是取一個數據的相反數,相反數在數學裡面定義為絕對值相等,符號相反的數:

>>>a = 200# 取相反數的常規寫法為:>>>-a-200# 本質上在底層是呼叫了__neg__()方法>>>a。__neg__()-200

'__neg__', '__pos__', '__abs__','__invert__','__trunc__','__floor__', '__ceil__', '__round__'

方法主要是給一個數據取正,說取正可能不太恰當,實際相當於不變。官方文件中描述的是+self:

>>>a = -200# 常規寫法為:>>>+a-200# 本質上在底層是呼叫了__pos__()方法>>>a。__pos__()-200

__neg__

方法主要用來取資料的絕對值,我們在使用

__pos__

函式時,在底層就是呼叫這個方法:

>>>a = -200>>>abs(a)200# 等價寫法>>>a。__abs__()200

__abs__

方法返回一個整數按位取反的結果,等價於

abs

符號。從數值上看,結果返回

__invert__

>>>a-200>>>~a199>>>a。__invert__()199

~

整數本身的相反數-1

__round__

__trunc__

這四個可以放在一塊學習。這四個方法主要用來實現資料的截斷。與這四個魔法方法相對應的有四個Python函式,Python的內建函式

__ceil__

會呼叫浮點型別的

__floor__

方法,math庫中的

round

函式、

__round__

函式、

trunc

函式則分別會呼叫

ceil

floor

__trunc__

,從而實現相應的功能,下面來詳細看一下。

__ceil__

方法用來實現資料的四捨五入,

__floor__

內建函式會呼叫物件的這個方法,該函式的引數為

__round__

,這裡的ndigits就是需要保留的四捨五入的位數,可以是正數、0或者負數,或者不傳遞:

# 這裡保留一位小數>>> round(7。23,1)7。2

由於浮點數在計算機中不能精確表達,有時候四捨五入得到的結果並不符合預期,這一點需要注意,例如:

# 按照四捨五入應該返回7。6,但是返回的是7。5>>> round(7。55,1)7。5# ndigits可以為0或者不傳遞,二者效果相同,但是返回的資料型別不同:>>> round(7。65,0)8。0# ndigits不傳遞,返回整數型別>>> round(7。65)8# ndigits還可以是負數,此時會對整數位進行四捨五入:# 這裡是對個位4進行四捨五入>>> round(234。2,-1)230。0>>> round(235。2,-1)240。0# 這裡是對十位3處進行四捨五入>>> round(234。2,-2)200。0# 這裡是對百位處四捨五入>>> round(234。2,-3)0。0

round

函式返回數值物件的整數部分,等價於

round(number[, ndigits])

math.trunc

方法和

物件.__trunc__()

方法返回結果往往是相同的。

>>> import math>>> math。trunc(7。4)7>>> math。trunc(7。5)7>>> math。trunc(7。6)7>>> math。trunc(-7。6)-7# 等價於>>> -7。6。__trunc__()-7# 等同於>>>-7。6。__int__()-7

__trunc__

函式接收一個浮點數,返回比浮點數小的最大整數,如果是正數,其結果和trunc函式相同,如果是負數,則不同。該函式如果接收一個整數,等價於呼叫整數的

__int__

方法,(注意浮點數沒有

math.floor

方法)。

# 比7。4小的最大整數是7>>> math。floor(7。4)7>>> math。floor(7。5)7>>> math。floor(7。7)7# 比-7。6小的最大整數是8 >>> math。floor(-7。6)-8>>> math。floor(-7)-7# 等價於>>> (-7)。__floor__()-7

__floor__()

函式接收一個浮點數,返回比浮點數大的最小整數。該函式如果接收一個整數,等價於呼叫整數的

__floor__()

方法,(注意浮點數沒有

math.ceil

方法)。

>>> math。ceil(7。4)8>>> math。ceil(7。5)8>>> math。ceil(7。6)8>>> math。ceil(-7。6)-7

__ceil__()

比較運算方法包括:

__ceil__()

。主要是用來執行比較運算的,分別對應了小於

比較運算方法:

、小於等於

比較運算方法:

、等於

'__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__'

、不等於

<

、大於

<=

、大於等於

==

。假設我們有兩個整數

!=

>

。則

>=

會在底層呼叫

x

方法、

y

在底層呼叫

x<y

方法、

x.__lt__(y)

會呼叫

x<=y

方法、

x.__le__(y)

會呼叫

x==y

x.__eq__(y)

會呼叫

x!=y

方法、

x.__ne__(y)

會呼叫

x>y

方法。

>>>x = 5>>>y = 4>>>x>>x。__lt__(y)False

上面的比較運算方法是數值型別的比較運算方法,Python內建物件object其實也定義了上面幾個方法,這裡我們也多提一句。我們知道,在python3中,如果不指定基類,所有自定義的類都預設繼承自object類。object類中內建了

x.__gt__(y)

這幾個方法。這就是說,在python3中,我們自定義的類預設都可以使用這幾個方法。不過可惜的是object中雖然對這些方法進行了定義,但是隻實現了

x>=y

x.__ge__(y)

兩個魔法方法,另外4個並沒有實現,因此對於我們自定義的類,預設都可以進行等於

'__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__'

和不等於

__eq__

的比較操作:

>>>class A():        pass    # 例項化產生兩個物件>>>a1 = A()>>>a2 = A()# 由於類A繼承自object,object中實現了__eq__方法,因此A的例項可以使用==>>>a1==a2False>>>a1!=a2True# 但是object中雖然定義了__gt__方法,但是並沒有實現方法的細節,所以A的例項無法使用>符號>>>a1>a2Traceback (most recent call last):  File “”, line 1, in     a1>a2TypeError: ‘>’ not supported between instances of ‘A’ and ‘A’

現在又有一個問題,object中的

'__ne__'

==

的比較規則是什麼?上面我們的例子中A的兩個例項a1和a2都不是數值型別,到底是如何進行

!=

==

的比較呢?答案是比較記憶體地址,如果記憶體地址相同,呼叫

!=

就會返回

==

,呼叫

!=

則會返回

==

。A的兩個例項物件a1和a2顯然是兩個例項物件,佔用了不同的記憶體空間,有不同的記憶體地址,所有使用

True

會返回

!=

>>>id(a1)2826922785184>>>id(a2)2826922785712

False

算數運算方法包括:

==

,這些方法分別對應了

FALSE

運算子。

>>>a = 3>>>b = 5>>>a+b8# 加法運算本質上是在呼叫__add__方法>>>a。__add__(b)Out[13]: 8>>>a-b-2# 減法運算本質上是在呼叫__sub__方法>>>a。__sub__(b)Out[15]: -2>>>a*b15# 乘法運算本質上是在呼叫__mul__方法>>>a。__mul__(b)15>>>a/b0。6# 除法運算本質上是在呼叫__truediv__方法>>>a。__truediv__(b)0。6>>>a//b0# 地板除法本質上是在呼叫__floordiv__方法>>>a。__floordiv__(b)0>>>b%a2# 取餘數運算是在呼叫__mod__方法b。__mod__(a)2    >>>divmod(b,a)(1, 2)# divmod函式本質上是在呼叫__divmod__方法>>>b。__divmod__(a)(1, 2)>>>a**b243# 乘方等價於使用pow函式>>>pow(a,b)243# 乘方的本質是在呼叫__pow__方法a。__pow__(b)Out[29]: 243

算數運算方法

反射算數運算方法包括:

算數運算方法

等。這些運算子和上面的算數運算子作用是類似的,但是互為映象或者說是反射關係。我們舉一個列子你就能明白了:對於兩個整數例項物件x和y,我們使用x+y本質上是呼叫

__add__、__sub__、__mul__、__truediv__、__floordiv__、__mod__、__divmod__、__pow__

,但是如果x沒有

+、-、*、/、//、%、divmod()、**

方法呢,這時候python直譯器會嘗試尋找y的

反射算數運算方法

方法,也就是呼叫

反射算數運算方法

從而完成算數運算,我們可以發現所有算數運算子都有一個對應的反射算數運算子,這就是為了在左側運算元找不到魔法方法時,可以從右側運算元中尋找反射魔法方法。這裡就不演示了。