Featured image of post 從零開始學Python (13) — 物件與類別:我們不一樣,每個人都有不同的際遇(中)

從零開始學Python (13) — 物件與類別:我們不一樣,每個人都有不同的際遇(中)

Day 13 物件與類別:我們不一樣,每個人都有不同的際遇(中)

註:本篇文章同步刊載於iT邦幫忙,為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10244495

先來解答昨天的問題吧!

我們可以修改上一篇的範例,並且新增一個compare方法,
由於比較的時候,我們利用self就可以取得現在的物件,
那麼從外面傳入的,我們直接將其稱為b,
要比較的就會是self.score的分數總和,和b.score的分數總和的關係。
這邊繼續介紹好用的小函式:
由於前面我們講過字典,要取所有的值的部分
(因為沒有加權嘛,就不用管科目了XD),
是用.values(),那要加總在一起,
我們可以用for … in …的方式一個一個加起來,
或者,我們可以使用sum()函式

它可以把一個可以算值的一組資料給加總起來。
於是一切就簡單啦!剩下的就是依照結果輸出。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Student():
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def readMyName(self):
        print('聽清楚了,我的名字是' + self.name + '!!!')

    def compare(self, b):
        diff = sum(self.score.values()) - sum(b.score.values())
        # 有冒號的式子如果底下程式碼只有一行,也可以選擇直接和判斷式寫成同一行
        if diff > 0: print(self.name + '贏了!')
        elif diff == 0: print('什麼?竟然平手?!')
        else: print('可...可惡,難道,這就是' + b.name + '真正的實力嗎?')

ming = Student('阿明', {'數學':55, '英文':70, '物理':55})
mei = Student('小美', {'數學':90, '英文':88, '物理':100})
howhow = Student('HowHow', {'數學':80, '英文':60, '物理':40})
print(ming.name)
print(mei.name)
print(how.name)
print('\n阿明 vs HowHow')
ming.compare(how)
print('\n阿明 vs 小美')
ming.compare(mei)
print('\n小美 vs HowHow')
mei.compare(how)

我們今天繼續來講物件與類別。
上一篇我們介紹了一個基本的類別是怎麼被做出來的,
也提到了初始化的函式,設定它們的屬性等做法。
在實際運用上,我們會遇到一個問題:
今天遇到更細項的屬性時,我們是否要將其設定到現有的類別呢?
如果這麼做的話,有時候會導致通用性不夠的問題。

例如:
對於一輛車子來說,它是Tesla的話,有可能會有自動駕駛功能,
但如果它是一般的車子的話,自動駕駛顯然不是一個正常會有的功能。
所以當我們有一個名為Car的類別時,
我們想要定義一個Tesla的Car,應該為其增設一個Tesla的類別,
而非直接在Car新增自動駕駛的功能。

但Tesla應該還是擁有Car的基本特性,所以我們可以利用這點,
避免掉重新設定一個全新的類別。這就是我們要介紹的方法:繼承
在繼承的概念裡,
原先Car的類別被稱為「父類別」、「超類別」或「基礎類別」,
(parent/super/base class)
而要做出來的Tesla被稱為「子類別」或「衍生類別」
(subclass/derived class)
定義子類別的話,只要在子類別的括號內加入父類別的名稱即可:

1
2
3
class Car():
    def whoami(self):
        print('I\'m a Car!')
1
2
class Tesla(Car):
    pass
1
2
3
4
car = Car()
tla = Tesla()
car.whoami()
tla.whoami()

讀者會發現,在Tesla中儘管尚未定義whoami(),
結果仍然會輸出,而輸出的結果其實是按照Car的whoami()來執行的:

1
2
3
C:\Users\Desolve>python fromzero.py
I'm a Car!
I'm a Car!

因為我們已經從Car這邊繼承過來了其屬性和方法,
所以Tesla也會有whoami的方法。
我們當然也可以把whoami做一下改變,並新增一些我們需要的東西:

1
2
3
class Car():
    def whoami(self):
        print('I\'m a Car!')
1
2
3
4
5
6
7
8
9
class Tesla(Car):
    def __init__(self):
        self.pilotmode = 1 # ON: 1, OFF: 0
    def whoami(self):
        print('I\'m a Tesla, not a trash car!')
    def autopilot_switch(self):
        self.pilotmode ^= 1 # ^是取XOR(互斥或),所以會在0和1之間切換
        if self.pilotmode == 0: print('Auto-pilot mode switch off!')
        else: print('Auto-pilot mode switch on!')
1
2
3
4
5
6
car = Car()
tla = Tesla()
car.whoami()
tla.whoami()
tla.autopilot_switch()
tla.autopilot_switch()

上面的示範中,我們為Tesla新增一個屬性,
用來表示自動駕駛模式是否開啟,
並提供一個切換開關的方法。但這是Tesla的東西,
所以Car並不會有autopilot_switch(),
讀者可以嘗試使用car.autopilot_switch()看看,應該會出現錯誤。

同時留意我們也重寫了一次whoami,
這個將父類別有的函式,重新給予定義的做法,
稱為override(覆寫/覆載)
整個執行的結果會如下所示:

1
2
3
4
5
C:\Users\Desolve>python fromzero.py
I'm a Car!
I'm a Tesla, not a trash car!
Auto-pilot mode switch off!
Auto-pilot mode switch on!

讀者可能會問:
「那如果我們想要覆寫父類別的方法,
又想用到原先的內容,那該怎麼做呢?」
這時候,我們就需要使用super()來取得父類別的東西了!
舉例來說,假設我們對每一輛車都會給它自己一個名字,
在whoami時,會先喊出自己的名字,我們可以修改上面的內容變成這樣:

1
2
3
4
5
6
class Car():
    def __init__(self, name):
        self.name = name
    def whoami(self):
        print('My name is ' + self.name)
        print('I\'m a Car!')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Tesla(Car):
    def __init__(self, name, mode):
        super().__init__(name) # 使用super來對name初始化,看起來稍微多此一舉,但可以保證對於name處理的一致性,之後如果要額外針對Car這個父類別修改時,就可以一起同時影響到Tesla這邊
        self.pilotmode = mode
    def whoami(self):
        super().whoami() # 先喊名字跟喊自己是輛車
        print('Also, I\'m a Tesla, not a trash car!') # 這兩行再做只有Tesla會做的事情
        print('Auto-pilot mode: ' + str(self.pilotmode))
    def autopilot_switch(self):
        self.pilotmode ^= 1
        if self.pilotmode == 0: print('Auto-pilot mode switch off!\n')
        else: print('Auto-pilot mode switch on!\n')
1
2
3
4
5
6
7
8
car = Car('CC')
tla = Tesla('TT', 0)
car.whoami()
print()
tla.whoami()
tla.autopilot_switch()
tla.whoami()
tla.autopilot_switch()

其執行結果應該像這樣:

1
2
3
C:\Users\Desolve>python fromzero.py
My name is CC
I'm a Car!
1
2
3
4
5
My name is TT
I'm a Car!
Also, I'm a Tesla, not a trash car!
Auto-pilot mode: 0
Auto-pilot mode switch on!
1
2
3
4
5
My name is TT
I'm a Car!
Also, I'm a Tesla, not a trash car!
Auto-pilot mode: 1
Auto-pilot mode switch off!

辛苦啦!在接下來的篇幅中,我們會再談談類別方法及靜態方法,
還有討論一下什麼時候該用類別/物件,什麼時候又該用模組的問題。

那我們就明天見囉!

工商時間:

抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)
Python Taiwan的連結第100篇的文章 底下,
公開分享到你的臉書、按讚該篇文章、並留言告訴我說,
「你最喜歡這一整個系列的哪一篇?為什麼?」或
「除了從LeetCode學演算法系列以外,
你還想要看到關於什麼方向的文章?」

超過20則留言的話 (有完成以上步驟的才算),我們就抽一組
「從Leetcode學演算法|進階篇」+「從Leetcode學演算法|面試篇」
課程的免費兌換券進行贈送!

期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)

容筆者工商一下,
「從Leetcode學演算法|進階篇」 開放預購啦!
這次選了40道難度加深的LeetCode題目,
同樣也會細部解說對應的技巧及須要掌握的演算法!
同時這次購買進階篇的話,
額外還加贈**「從Leetcode學演算法|面試篇」** !
當中包含了面試準備須知分享及訪談國內外不同經驗的工程師
讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作
初學想轉職 還是正在工作 ,都能夠從中得到收穫呦!
有興趣的朋友可以使用下面的早鳥優惠~
「從Leetcode學演算法|進階篇」+「從Leetcode學演算法|面試篇」
https://bit.ly/advleetcode

「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠:
https://bit.ly/allleetcode

共發表了 171 篇文章 ‧ 總計 311.6k
使用 Hugo 建立
主題 StackJimmy 設計