摘要:一運算符重載基礎運算符重載對已有的運算符進行重新定義,賦予其另一種功能,以適應不同的數據類型。重載一元運算符重載一元運算符只需實現相應的特殊方法,這些特殊方法只有一個參數。
導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。
本文重點:
1、掌握運算符重載的定義和作用,以及Python對其的內部限制;一、運算符重載基礎
2、掌握一元運算符重載設計思路;
3、理解中綴運算符重載過程中鴨子類型和白鵝類型思想的運用并掌握。
運算符重載:對已有的運算符進行重新定義,賦予其另一種功能,以適應不同的數據類型。
重載的作用:令用戶定義的對象能夠使用中綴運算符(如 + 和 | )或一元運算符(如 - 和 ~ )等運算符。
為了做好靈活性、可用性和安全性方面的平衡,Python對運算符重載施加了一些限制:
不能重載內置類型的運算符;
能新建運算符,只能重載現有運算符;
某些運算符不能重載,如is、and、or和not(不過位運算符&、| 和 ~可以)。
二、一元運算符 1、常見的一元運算符-(__neg__),一元取負算術運算符。例:若 x 是 -2,則 -x==2。
+(__pos__),一元取正算術運算符。通常x==+x。
~(__invert__),對整數按位取反,~x== -(x+1)。例:若 x 是 -2,則 ~x==1。
另外,Python語言參考手冊將內置的abs()函數列為一元運算符,它對應的特殊方法是__abs__。
2、重載一元運算符重載一元運算符只需實現相應的特殊方法,這些特殊方法只有self一個參數。
重載應遵循運算符的一個基本規則:始終返回一個新對象。
即,不能修改self,要創建并返回合適類型的新實例。
下面我們以第10章的多維向量類為例重載一元運算符:
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)3、x和+x不相等的情況
算術運算上下文的精度變化可能導致 x 不等于 +x
Python 3.4 為 Decimal 算術運算設定的默認精度是28,這里因為+x使用上下文的精度導致相等性判斷返回False。
counter實例不含零值和負值計算器
通過上面的實例能夠看到counter實例ct經過零值和負值的賦值之后,再經過+x運算后發現ct實例中的非負數對象均消失了。事實上一元運算符 + 等同于加上一個空 Counter。當Counter相加時,Python解釋器從實用性角度出發會把負值和零值的計數從結果中剔除。
現在我們仍以第10章的多維向量為例進行中綴運算符加號“+”的重載。
重載加法的目標分析:
當多維向量類是操作數時,多維向量應支持與同類向量的加法;
同時多維向量類還應支持與可迭代對象的加法;
此外當可迭代對象是操作數的時候,多維對象應具備__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
2、重載乘法__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 解釋器對眾多比較運算符(==、 !=、 >、 <、 >=、 <=) 的處理與前文類似, 不過在兩個方面有重大區別。
正向和反向調用使用的是同一系列方法。這方面的規則如下表所示。例如,對 == 來說,正向和反向調用都是 _eq_ 方法,只是把參數對調了;而正向的 _gt_ 方法調用的是反向的 __lt__方法, 并把參數對調。
對 == 和 != 來說,如果反向調用失敗,Python 會比較對象的 ID,而不拋出 TypeError。
1、重載等號__eq__現在我們仍以第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 NotImplemented2、了解object中__ne__的實現
def __ne__(self, other): eq_result = self == other if eq_result is NotImplemented: return NotImplemented else: return not eq_result五、增量賦值運算符 1、重載加等于__iadd__
現在我們仍以第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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44565.html
摘要:導語本文章匯總了本人在學習基礎之緒論篇數據結構篇函數篇面向對象篇控制流程篇和元編程篇學習筆記的鏈接,打算入門的朋友們可以按需查看并交流。 導語:本文章匯總了本人在學習Python基礎之緒論篇、數據結構篇、函數篇、面向對象篇、控制流程篇和元編程篇學習筆記的鏈接,打算入門Python的朋友們可以按需查看并交流。 第一部分:緒論篇 1、Python數據模型 第二部分:數據結構篇 2、序列構成...
摘要:前言數據模型其實是對框架的描述,它規范了這門語言自身構件模塊的接口,這些模塊包括但不限于序列迭代器函數類和上下文管理器。上述類實現了方法,它可用于需要布爾值的上下文中等。但多虧了它是特殊方法,我們也可以把用于自定義數據類型。 《流暢的Python》筆記。本篇是Python進階篇的開始。本篇主要是對Python特殊方法的概述。 1. 前言 數據模型其實是對Python框架的描述,它規范了...
摘要:找到模塊文件之后,將其編譯成字節碼,就是那個文件里面的關于字節碼,下面會介紹,請繼續閱讀。當然,如果根本就沒有找到同名的源文件,只有字節碼文件,那么就只能運行這個了。執行就是前面已經編譯的模塊字節碼文件,順理成章要執行了。 不管是用import還是用from mmmm import *的方式導入模塊,當程序運行之后,回頭在看那個存儲著mmmm.py文件的目錄中(關于mmmm.py文件可...
摘要:本文重點了解數據模型和接口的概念掌握特殊方法的定義,作用和基本用法。一基本概念數據模型是數據特征的抽象,這里是對框架的描述。數據模型規范了自身構建模塊的接口,模塊包括但不限于序列迭代器函數類和上下文管理器。 導語:本文章記錄了本人在學習Python基礎之緒論篇的重點知識及個人心得,以加深自己的理解。 本文重點: 1、了解Python數據模型和接口的概念;2、掌握特殊方法的定義,作用和基...
摘要:函數的基本結構中的函數基本結構函數名參數列表語句幾點說明函數名的命名規則要符合中的命名要求。在中,將這種依賴關系,稱之為多態。不要期待在原處修改的函數會返回結果比如一定要之用括號調用函數不要在導入和重載中使用擴展名或路徑。 在本教程的開始部分,就已經引入了函數的概念:《永遠強大的函數》,之所以那時候就提到函數,是因為我覺得函數之重要,遠遠超過一般。這里,重回函數,一是復習,二是要在已經...
閱讀 1629·2019-08-30 15:54
閱讀 2374·2019-08-30 15:52
閱讀 2048·2019-08-29 15:33
閱讀 3042·2019-08-28 17:56
閱讀 3237·2019-08-26 13:54
閱讀 1675·2019-08-26 12:16
閱讀 2449·2019-08-26 11:51
閱讀 1645·2019-08-26 10:26