1. 程式人生 > >【python小課堂專欄】python小課堂18 - 面向物件篇(一)

【python小課堂專欄】python小課堂18 - 面向物件篇(一)

python小課堂18 - 面向物件篇(一)

前言

又到週末了!時間過得好快啊…依稀記得公眾號剛開時,有個大學同學跟我說,介紹的太詳細了,什麼時候才能介紹到面向物件的章節啊!結果時間飛逝,2018年12月1日,距離開號正式寫文章的時間(2018年9月21號)已經過去2個多月了…

好了廢話不多說…依然繼續迴歸python小課堂知識分享,這次開始了重頭戲,就是程式設計屆的重要思想 — 面向物件(沒錯,它是一種程式設計的思想)。時常在程式設計屆,經常聽到有人說找不到女朋友怎麼辦?對於程式設計師來說,so easy啊,直接new 一個“物件”出來就行了!而在python中,物件的概念也是非常重要的,因為在python中有著萬物即物件的概念,所有東西都可以看做是物件!今天就來演示下,如何用程式碼創建出一個女朋友來!~(屌絲!!捂臉跑…)

面向物件程式設計

什麼是面向物件程式設計呢?之前的小課堂中,我一直在強調一個概念,就是計算機中的程式碼就是現實世界的對映,而物件也不例外。舉個例子來說,比如現實世界的車,賓士,寶馬,瑪莎拉蒂,阿斯頓·馬丁,這些品牌所造出來的車,都屬於汽車這一型別,而所謂的汽車這一型別對映到程式設計世界就是物件。再舉個栗子,前言說到的女朋友,也可以看做一個型別,對應到程式碼中也可以是一個物件。。所以型別,我們一般在程式設計中簡稱類, 類 = 面向物件。

在這裡插入圖片描述

定義一個女朋友(建立物件)

自己用程式碼建立一個女朋友吧!你的女朋友,你當然知道她的姓名,年齡,身高,生日等等,這裡所說的都是描述女朋友的特徵,對應到python程式碼中可以理解為女票就是一個物件,而特徵即為這個物件的特有屬性。

,在Python中用class作為關鍵詞表示。下面來看下程式碼演示:


class GirlFriend():
    name = '女兒國國王'      # 姓名
    age =  300              # 年齡
    height = '177'          # 身高
    birthday = '1718-12-01' # 出生

    # 行為,說出自己的特徵
    def say_feature(self):
        print(f'我的姓名:{self.name}')
        print(f'我的年齡:{self.age}')
print(f'我的身高:{self.height}') print(f'我的生日:{self.birthday}') girlFriend = GirlFriend() # 例項化 girlFriend.say_feature() # 呼叫物件的方法

最終輸出:
>>>我的姓名:女兒國國王
>>>我的年齡:300
>>>我的身高:177
>>>我的生日:1718-12-01

① 可以看到上述程式碼段中,class 後面定義了類的名字女朋友,一般定義物件時,命名符合首字母大寫,後面每個單詞首字母大寫,程式設計中稱之為駝峰命名法。例如girlfriend,你就要寫成GirlFriend。名字定義完後面跟上小括號,需要注意的是小括號中只能傳入另一種物件,而非類似函式的形參。後續會講到繼承,到時候就懂了。

② 在類中,我定義了一些女朋友的特徵,並且給了她一個行為,她可以自己說出自己的特徵。這個行為和我們定義的函式一樣,也是通過def定義,在類中,我們可以將之成為方法,方法和函式的寫法一樣,但是概念上稍有差異。方法是從設計層面定義得,而函式是從執行過程中設計的,瞭解即可。然而呼叫自身的屬性時,必須要在方法中傳入形參self,只有通過self.xxx才可以呼叫變數(name,age…),也就是特徵。否則可以自行嘗試,直接呼叫變數名稱會報錯。

③ 如何呼叫,讓女朋友自己說話?girlFriend = GirlFriend() 通過這樣的寫法,將物件進行例項化,然後可以通過賦予的變數加以.來呼叫她內部的方法。可以看到上段程式碼最後一行就是呼叫方式。

思考一個問題,當我們有一個女朋友時,此時建立多個例項物件會怎麼樣呢?他們會屬於一個物件嗎?來看下:

girlFriend = GirlFriend()   # 例項化
girlFriend1 = GirlFriend()
girlFriend2 = GirlFriend()

還記得python中自帶的id()函式嗎,可以通過此函式來檢視對應的記憶體地址,結果如下:

print(id(girlFriend))
print(id(girlFriend1))
print(id(girlFriend2))

>>> 1361650701648
>>> 1361650701760
>>> 1361650631512

顯而易見!雖然公用的是一個女票作為類來進行例項化,但是到具體的物件時,她們之間的記憶體地址卻不盡相同。

女朋友的初始化行為(建構函式)

什麼叫女朋友的初始化行為呢?還是用上面的例子來舉例說明,女兒國國王,初始的設定就是為了娶到唐僧,然後嘿嘿嘿…吃掉。來看下程式碼:

class GirlFriend():
    name = '女兒國國王'      # 姓名
    age =  300              # 年齡
    height = '177'          # 身高
    birthday = '1718-12-01' # 出生

    def __init__(self):
        print('我要先把唐僧娶了,嘿嘿嘿....然後在吃了!')

    # 行為,說出自己的特徵
    def say_feature(self):
        print(f'我的姓名:{self.name}')
        print(f'我的年齡:{self.age}')
        print(f'我的身高:{self.height}')
        print(f'我的生日:{self.birthday}')
        
# 例項化時,會輸出我要先把唐僧娶了,嘿嘿嘿....然後在吃了!
girlFriend = GirlFriend()   

>>> 我要先把唐僧娶了,嘿嘿嘿....然後在吃了!

可以看到我在女朋友的類中新增了一個 def init(self) 方法,此方法見名知意,init是初始的意思,也就是常說的構造方法。什麼意思呢?每當我們例項化物件時,預設會呼叫此方法,一般用於類呼叫時候的初始操作,比如女兒國國王的初始任務就是對唐僧下手!

需要注意的幾點如下:

① __init__方法可以手動呼叫,但是沒有必要。

girlFriend = GirlFriend()   # 例項化
girlFriend.__init__()       # 可以通過呼叫此方法看下

>>> 我要先把唐僧娶了,嘿嘿嘿....然後在吃了!
>>> 我要先把唐僧娶了,嘿嘿嘿....然後在吃了!

init()的預設返回值:None

girlFriend = GirlFriend()   # 例項化
print(girlFriend.__init__())
print(type(girlFriend.__init__()))

>>> 我要先把唐僧娶了,嘿嘿嘿....然後在吃了!
>>> None
>>> <class 'NoneType'>

③ 嘗試給init新增返回值,報錯,可以看到只能返回None,不能返回其他型別。

在這裡插入圖片描述


對於女兒國國王為女朋友的例子,如果我作為她背後的黑幕,每次都想讓她的初始任務聽命於我呢,也就是所謂的每次例項化時,再將具體的任務分配給她,如何做到?於是有了下面的程式碼:
class GirlFriend():
    name = '女兒國國王'      # 姓名
    age =  300              # 年齡
    height = '177'          # 身高
    birthday = '1718-12-01' # 出生

    def __init__(self,task_name):
        print(task_name)

    # 行為,說出自己的特徵
    def say_feature(self):
        print(f'我的姓名:{self.name}')
        print(f'我的年齡:{self.age}')
        print(f'我的身高:{self.height}')
        print(f'我的生日:{self.birthday}')

girlFriend = GirlFriend('我要先把唐僧娶了,嘿嘿嘿....')   # 例項化
girlFriend1 = GirlFriend('然後在吃了!')   # 例項化

>>> 我要先把唐僧娶了,嘿嘿嘿....
>>> 然後在吃了!

通過構造方法的傳參,可以實現我們對一個物件例項化時進行可控的引數傳入。但是需要注意,如果在構造方法處定義了引數,那麼例項化物件時一定要傳入對應的數量引數,否則會報錯缺少引數的錯誤,如下:

在這裡插入圖片描述

類變數與例項變數的對比

什麼是類變數?什麼是例項變數呢?還是迴歸到“女兒國國王”女朋友的例子上:

class GirlFriend():
    name = '女兒國國王'      # 姓名
    age =  300              # 年齡
    height = '177'          # 身高
    birthday = '1718-12-01' # 出生

    # 初始化構造方法
    def __init__(self,name,age):
        self.name = name
        self.age = age

    # 行為,說出自己的特徵
    def say_feature(self):
        print(f'我的姓名:{self.name}')
        print(f'我的年齡:{self.age}')
        print(f'我的身高:{self.height}')
        print(f'我的生日:{self.birthday}')

girlFriend = GirlFriend('人類女孩',18)   # 例項化
girlFriend.say_feature()
print(f'類變數姓名:{GirlFriend.name}')
print(f'類變數年齡:{GirlFriend.age}')

>>> 我的姓名:人類女孩
>>> 我的年齡:18
>>> 我的身高:177
>>> 我的生日:1718-12-01
>>> 類變數姓名:女兒國國王
>>> 類變數年齡:300

所謂的類變數就是指上述程式碼中沒有定義在方法中的變數,而直接暴露在類中定義的變數,例如height = ‘177’。例項變數是指定義在類方法中的變數,例如構造方法中我們傳入的name和age。通常使用self.xx = xx將外界引數繫結到例項變數中。可以看到上面程式碼中的結果,通過例項化傳入的變數,最終呼叫列印說話時,以例項變數為準,而非類變數。

Tips:
實際上,目前這個女朋友的例子中的類變數寫的並沒有實際意義,只是為了演示而演示,從設計的角度出發,類變數怎麼可能選擇姓名和名稱這種不固定的值呢?可以思考下,既然是類的變數,那應該是一個種類所具體有的特徵,而非具體到某一特徵,比如姓名,一個人可能一生會談好幾次戀愛,每次女朋友的名字都是會變得,那你能把名字作為所有女朋友這一類共同特徵嗎!肯定是不行的,所以類變數定義時應該是選取共同特徵時的變數去定義,我這裡只是舉例而已。

總結

類最基本的作用:封裝,類就像一個模板,說白了就是程式碼共用的一套寫法,而類就是現實世界的抽象!什麼是抽象!!!抽象在程式設計世界中就是將所有有共同性的東西抽出來封裝成一個模板!而例項化後的物件才是具體的實現。(程式設計思想,非專業人員瞭解即可。)

至此完!


有想學python的同學,歡迎關注公號:

在這裡插入圖片描述