導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。
本文重點:python
一、掌握運算符重載的定義和做用,以及Python對其的內部限制;
二、掌握一元運算符重載設計思路;
三、理解中綴運算符重載過程當中鴨子類型和白鵝類型思想的運用並掌握。
運算符重載:對已有的運算符進行從新定義,賦予其另外一種功能,以適應不一樣的數據類型。
重載的做用:令用戶定義的對象可以使用中綴運算符(如 + 和 | )或一元運算符(如 - 和 ~ )等運算符。
爲了作好靈活性、可用性和安全性方面的平衡,Python對運算符重載施加了一些限制:安全
不能重載內置類型的運算符
;能新建運算符,只能重載現有運算符
;某些運算符不能重載,如is、and、or和not(不過位運算符&、| 和 ~能夠)
。另外,Python語言參考手冊將內置的abs()函數列爲一元運算符,它對應的特殊方法是__abs__。函數
重載一元運算符只需實現相應的特殊方法,這些特殊方法只有self一個參數。重載應遵循運算符的一個基本規則:始終返回一個新對象
。
即,不能修改self,要建立並返回合適類型的新實例。學習
下面咱們以第10章的多維向量類爲例重載一元運算符:spa
import math class Vector: #排版須要省略中間代碼 def __abs__(self): return math.sqrt(sum(x*x for x in self)) def __neg__(self): return Vector(-x for x in self) def __pos__(self): return Vector(self) def __invert__(self): return Vector(-x-1 for x in self)
Python 3.4 爲 Decimal 算術運算設定的默認精度是28,這裏由於+x使用上下文的精度致使相等性判斷返回False。設計
經過上面的實例可以看到counter實例ct通過零值和負值的賦值以後,再通過+x運算後發現ct實例中的非負數對象均消失了。事實上一元運算符 + 等同於加上一個空 Counter。當Counter相加時,Python解釋器從實用性角度出發會把負值和零值的計數從結果中剔除。code
如今咱們仍以第10章的多維向量爲例進行中綴運算符加號「+」的重載。
重載加法的目標分析:orm
當多維向量類是操做數時,多維向量應支持與同類向量的加法
;同時多維向量類還應支持與可迭代對象的加法
;此外當可迭代對象是操做數的時候,多維對象應具有__radd__如此來調用多維向量類中的__add__方法
。重載加法的流程圖設計:
設計的重點在於採用鴨子類型思想。當多維向量類與非數值類相加時,多維向量類沒法處理異類加法運算能夠將加法運算交給右操做數的類處理。由於右操做數存在能夠處理這種異類加法的可能。對象
重載加法的代碼實現:繼承
from itertools import zip_longest class Vector: #排版須要省略中間代碼 def __add__(self, other): try: return Vector(a+b for a,b in zip_longest(self,other,fillvalue=0)) except TypeError: return NotImplemented def __radd__(self, other): return self+other
二、重載乘法__mul__
重載加法的目標分析:
當多維向量類是操做數時,多維向量應支持與同類向量的乘法
;同時多維向量類還應支持與可迭代對象的加法
;此外當可迭代對象是操做數的時候,多維對象應具有__rmul__如此來調用多維向量類中的__mul__方法
。注意:咱們對多維向量重載的乘法是針對數論中的實數類型進行運算,此時能夠採用白鵝類型顯式檢查對象的抽象基類是否爲numbers.Real,代碼實現以下:
import numbers class Vector: #排版須要省略中間代碼 def __mul__(self, other): if isinstance(other,numbers.Real): return Vector(x*other for x in self) else: return NotImplemented def __rmul__(self, other): return self*other
Tips:通常來講只有當處理與self不一樣類型的操做數時,須要建立反向方法處理。不然沒有必要建立反向方法。
Python 解釋器對衆多比較運算符(==、 !=、 >、 <、 >=、 <=) 的處理與前文相似, 不過在兩個方面有重大區別。
如今咱們仍以第10章的多維向量爲例進行中綴運算符等號「=」的重載。
重載等號的返回爲True的條件:
等號兩端對象爲同類對象
;等號兩端對象中的每一個元素都必須對應相等
。注意:若Vector處理等號不爲True,應該返回NotImplemented交由Python處理。若是反向調用返回 NotImplemented,Python 會使用後備機制比較對象的 ID,做最後一搏。
重載等號的代碼實現以下:
class Vector: #排版須要省略中間代碼 def __eq__(self, other): if isinstance(other,Vector): return len(self)==len(other) and all(x==y for x,y in zip(self,other)) else: return NotImplemented
def __ne__(self, other): eq_result = self == other if eq_result is NotImplemented: return NotImplemented else: return not eq_result
如今咱們仍以第10章的多維向量爲例進行中綴運算符加等於「+=」的重載。
重載加等於設計要求:
加等於右側的對象與左側的Vector類是同類對象或可迭代對象
;不然拋出TypeError,顯示沒法進行加等於計算
。下面以BingoCage的子類AddableBingoCage爲例實現__iadd__,你們沒必要在乎這個子類,重點在於理解__iadd__實現的思路:
import itertools from tombola import Tombola from bingo import BingoCage class AddableBingoCage(BingoCage): def __add__(self, other): if isinstance(other, Tombola): return AddableBingoCage(self.inspect() + other.inspect()) #self.inspect()繼承自BingoCage,返回當前元素組成的有序元組。 else: return NotImplemented def __iadd__(self, other): if isinstance(other, Tombola): other_iterable = other.inspect() else: try: other_iterable = iter(other) except TypeError: self_cls = type(self).__name__ msg = "right operand in += must be {!r} or an iterable" raise TypeError(msg.format(self_cls)) self.load(other_iterable) return self