關注公眾號:
用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
上面的比較運算方法是數值型別的比較運算方法,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 “
現在又有一個問題,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的
反射算數運算方法
方法,也就是呼叫
反射算數運算方法
從而完成算數運算,我們可以發現所有算數運算子都有一個對應的反射算數運算子,這就是為了在左側運算元找不到魔法方法時,可以從右側運算元中尋找反射魔法方法。這裡就不演示了。