天天看點

《手把手陪您學Python》41——類方法與執行個體方法

在上一篇《手把手陪您學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()
        ----> 2 small_mario.jump()
        
        TypeError: jump() takes 0 positional arguments but 1 was given
           
In [6]: small_mario.attack("Small mario")
Out[6]: ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-24-8478b32ee2d8> in <module>
        ----> 1 small_mario.attack("Small mario")
        
        TypeError: attack() takes 1 positional argument but 2 were given
           
In [7]: small_mario.eat("Small mario", "red mushroom")
Out[7]: ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-25-4b4a74507a8b> in <module>
        ----> 1 small_mario.eat("Small mario", "red mushroom")
        
        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):   # 使用非self名稱進行驗證
        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>
         ----> 1 Mario.jump()
                 
         TypeError: jump() missing 1 required positional argument: 'self'
           

以上就是我們對于類方法以及執行個體方法的介紹,正是因為有強大的類方法的加持,才讓面向對象程式設計能夠精準地模拟現實生活中的情況,并變得無比強大。

下一篇,我們将會繼續對類方法的其他内容進行介紹,包括執行個體屬性、魔法方法等,敬請關注。

《手把手陪您學Python》41——類方法與執行個體方法

感謝閱讀本文!如有任何問題,歡迎留言,一起交流讨論^_^

要閱讀《手把手陪您學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》26——自定義函數

《手把手陪您學Python》27——自定義函數的參數

《手把手陪您學Python》28——自定義函數的傳回值

《手把手陪您學Python》29——匿名函數

《手把手陪您學Python》30——子產品

《手把手陪您學Python》32——檔案的讀取

《手把手陪您學Python》33——檔案的關閉

《手把手陪您學Python》34——檔案的寫入

《手把手陪您學Python》35——資料的存儲

《手把手陪您學Python》36——錯誤和異常處理

《手把手陪您學Python》37——程式的重構

《手把手陪您學Python》38——第二階段小結

《手把手陪您學Python》39——面向對象

《手把手陪您學Python》40——類的定義、屬性與執行個體化

For Fans:關注“亦說Python”公衆号,回複“手41”,即可免費下載下傳本篇文章所用示例語句。

《手把手陪您學Python》41——類方法與執行個體方法

亦說Python——Python愛好者的學習分享園地