在上一篇《手把手陪您學Python》40——類的定義、屬性與實例化中,我們學習了面向對象編程的基礎知識,了解了類的屬性以及實例化屬性等,今天我們將會主要介紹類的方法以及實例方法。
1、類的方法:
類的方法其實也可以認為是類具有的某種特徵,與類的屬性不同的是,這種特徵除了可以用變量進行描述以外,還可以做更多的「事情」,而這些事情是通過定義函數的方式來實現的。
也就是說,如果類的屬性是可以通過實例訪問的變量,那麼類的方法就是可以通過實例訪問的函數。
類中的函數就稱為方法,我們之前學習的有關函數的一切都適用於方法。
雖然我們之前也嘗試過對函數和方法的區別進行過描述,但也只是為了讓初學的我們更好地理解和使用函數與方法,其實兩者的界限並不是那麼地清晰,而且從英文上的表示來看,兩者也都是function。所以,後面我們會逐漸淡化這兩者的區別,無論是說函數還是方法,其實指的是一回事。
讓我們通過實例看一看,類的方法是如何通過定義函數的方式來實現的,又可以做哪些事情。
我們選取馬裡奧的三個技能作為馬裡奧類的方法,包括可以跳躍、可以攻擊,還可以吃東西,作為對馬裡奧類的補充。這時,對於馬裡奧類的描述就比較完整了:
In [1]: class Mario: life = 3 cap = "red" def jump(): print("Jumping!") def attack(name): print("{} attacked an anomy!".format(name)) def eat(name, food): print("{} ate a {}!".format(name, food)) print("{} became bigger!".format(name))運行程序我們就完成了馬裡奧類的完整的定義。
由於函數是可以自定義參數的,所以類的方法也同樣可以不需要參數、一個參數或者多個參數。
函數內的語句既是對函數的定義,也是對類方法的定義,也就是這個類可以做的「事情」。
在上面的實例中,每個類方法執行的內容都是列印一段字符串,但是在真正的遊戲中,就不僅僅是這麼簡單的一句指令了,而是一系列更為複雜的程序來實現畫面的變化、背景音樂的配合,甚至還要觸發牆被頂破以及敵人被壓死的效果等等。
如果更進一步地,不是在控制一個動畫效果,而是控制一個真實的機器人馬裡奧,那麼這裡就是控制各類設備和傳感器的指令,進而控制機器人馬裡奧的行為。
所以說,在類的方法中,通過定義函數的方式,可以做很多的事情,遠比類的屬性要複雜和強大得多。
2、類方法的引用
引用類方法和我們之前學過的各種方法的引用方式一樣,只要把對象名稱改為類名稱或者實例名稱就好了,如果方法中需要參數,就在括號中加上參數。
類名稱.類方法(參數1, 參數2, 參數3...)
我們可以引用一下剛剛定義的馬裡奧的三個方法,如果在定義方法的時候要求輸入參數,我們也相應地輸入參數即可。
In [2]: Mario.jump()Out[2]: Jumping!
In [3]: Mario.attack("Mario")Out[3]: Mario attacked an anomy!
In [4]: Mario.eat("Mario", "red mushroom")Out[4]: Mario ate a red mushroom! Mario became bigger!如果我們還想給馬裡奧賦予更多的方法,或者希望在現有的方法中擴展新的內容,就像我們之前自定義函數一樣,自行添加相應語句就可以了,這裡就不繼續演示了。
這時,可以回看一下《手把手陪您學Python》39——面向對象中的內容,我們在講解的過程中使用到了很多的括號,當時說大家可以先不用理會其中的內容,等講到後面的時候自然就會了解了。包括括號裡標記的「對象」、「屬性」、「方法」,現在看起來就會對其中的概念非常清晰了。
像洗衣服過程中括號裡的內容,實際上就是我們剛剛講的對洗衣機類和人類的方法的引用。
1、人打開洗衣機門(人.打開洗衣機門)
2、人把衣服放進去(人.把衣服放進去)
3、人關上洗衣機門(人.關上洗衣機門)
4、人啟動電源(人.啟動電源)
5、洗衣機清洗衣服(洗衣機.清洗衣服)
6、洗衣機甩乾衣服(洗衣機.甩乾衣服)
7、洗衣機烘乾衣服(洗衣機.烘乾衣服)
既然已經定義好了類的方法,那麼就像實例可以引用類屬性一樣,實例應該也可以引用同樣的類方法,讓我們看一下是不是這樣:
In [5]: small_mario = Mario() small_mario.jump()Out[5]: TypeError Traceback (most recent call last) <ipython-input-23-11dbe964307a> in <module> 1 small_mario = Mario() TypeError: jump() takes 0 positional arguments but 1 was givenIn [6]: small_mario.attack("Small mario")Out[6]: TypeError Traceback (most recent call last) <ipython-input-24-8478b32ee2d8> in <module> TypeError: attack() takes 1 positional argument but 2 were givenIn [7]: small_mario.eat("Small mario", "red mushroom")Out[7]: TypeError Traceback (most recent call last) <ipython-input-25-4b4a74507a8b> in <module> TypeError: eat() takes 2 positional arguments but 3 were given可以看到,雖然我們將馬裡奧類實例化成了小馬裡奧,但是在引用類方法的時候都出現了錯誤,而且錯誤類型都提示「只有n個位置參數但應該有n+1個位置參數」。
那麼為什麼會報錯,這多出來的1個位置參數又是什麼呢?
這是因為實例引用類方法與實例引用類屬性有一些不同,雖然實例可以直接引用「類屬性」,但是實例是不能夠直接「類方法」的,而只能引用「實例方法」。
3、實例方法
實例方法的定義與類方法有所不同。
類方法的定義與我們自定義函數時參數的設置是一樣的,可以沒有參數,也可以有一個或者多個參數。而在定義實例方法時,每一個方法都默認要有一個「self」參數,而且必須是要作為第一個參數的。這個「self」參數就是報錯提示中多出來的那個參數。
這個self代表的就是實例本身。
也就是說,當我們定義實例方法時,實例本身就是實例方法的一個參數,而且默認是第一個參數。當實例調用這個方法時,會自動將實例傳入這個self參數中。每個實例方法都會自動將實例傳入self參數中,它是一個指向實例本身的引用,讓實例能夠訪問類中的屬性和方法。
self並不是Python的關鍵字,把他換成其他名稱也是可以的,只不過在Python中約定俗成地使用self代表實例本身,所以我們也照常使用就可以了。
讓我們用實例方法的定義方式將上面的類方法進行修改,也就是在每一個方法中都在第一個參數的位置增加self參數,就可以得到下面的實例方法。同時,為了驗證不使用self名稱也不影響調用,在其中一個參數的設置中使用了其他名稱加以驗證,但僅此一次。
In [8]: class Mario: life = 3 cap = "red" def jump(self): print("Mario is jumping!") def attack(good, name): print("Mario attacked an anomy!") def eat(self, name, food): print("Mario ate a {}!".format(food)) print("{} became bigger!".format(name))這時再讓實例去引用這些方法,就能得到我們預期的結果了。
In [9]: small_mario = Mario()Out[9]: small_mario.jump() Mario is jumping!
In [10]: small_mario.attack("Small mario")Out[10]: Mario attacked an anomy!
In [11]: small_mario.eat("Small mario", "red mushroom")Out[11]: Mario ate a red mushroom! Small mario became bigger!所以說,一旦一個類被實例化,就可以像使用函數一樣使用這個類,函數的參數就是實例。如果用公式和例子描述的話可能會更清晰一些。
實例.實例方法() == 類.實例方法(實例)
In [12]: print(small_mario.jump() == Mario.jump(small_mario))Out[12]: Mario is jumping! Mario is jumping! True相應地,因為現在定義的是實例方法,如果此時調用類方法的話就會報錯了。
In [13]: Mario.jump()Out[13]: TypeError Traceback (most recent call last) <ipython-input-38-d2cb2ba47b0e> in <module> TypeError: jump() missing 1 required positional argument: 'self'以上就是我們對於類方法以及實例方法的介紹,正是因為有強大的類方法的加持,才讓面向對象編程能夠精準地模擬現實生活中的情況,並變得無比強大。
下一篇,我們將會繼續對類方法的其他內容進行介紹,包括實例屬性、魔法方法等,敬請關注。
感謝閱讀本文!如有任何問題,歡迎留言,一起交流討論^_^
要閱讀《手把手陪您學Python》系列文章的其他篇目,請關注公眾號點擊菜單選擇,或點擊下方連結直達。
《手把手陪您學Python》1——為什麼要學Python?
《手把手陪您學Python》2——Python的安裝
《手把手陪您學Python》3——PyCharm的安裝和配置
《手把手陪您學Python》4——Hello World!
《手把手陪您學Python》5——Jupyter Notebook
《手把手陪您學Python》6——字符串的標識
《手把手陪您學Python》7——字符串的索引
《手把手陪您學Python》8——字符串的切片
《手把手陪您學Python》9——字符串的運算
《手把手陪您學Python》10——字符串的函數
《手把手陪您學Python》11——字符串的格式化輸出
《手把手陪您學Python》12——數字
《手把手陪您學Python》13——運算
《手把手陪您學Python》14——交互式輸入
《手把手陪您學Python》15——判斷語句if
《手把手陪您學Python》16——循環語句while
《手把手陪您學Python》17——循環的終止
《手把手陪您學Python》18——循環語句for
《手把手陪您學Python》19——第一階段小結
《手把手陪您學Python》20——列表
《手把手陪您學Python》21——元組
《手把手陪您學Python》22——字典
《手把手陪您學Python》23——內置序列函數
《手把手陪您學Python》24——集合
《手把手陪您學Python》25——列表推導式
《手把手陪您學Python》26——自定義函數
《手把手陪您學Python》27——自定義函數的參數
《手把手陪您學Python》28——自定義函數的返回值
《手把手陪您學Python》29——匿名函數
《手把手陪您學Python》30——模塊
《手把手陪您學Python》31——文件的打開
《手把手陪您學Python》32——文件的讀取
《手把手陪您學Python》33——文件的關閉
《手把手陪您學Python》34——文件的寫入
《手把手陪您學Python》35——數據的存儲
《手把手陪您學Python》36——錯誤和異常處理
《手把手陪您學Python》37——程序的重構
《手把手陪您學Python》38——第二階段小結
《手把手陪您學Python》39——面向對象
《手把手陪您學Python》40——類的定義、屬性與實例化
長按下方二維碼,關注「亦說Python」。
回復「手41」,即可免費下載本篇文章所用示例語句。
歡迎關注「亦說Python」
Python愛好者的學習分享園地