iT邦幫忙

2022 iThome 鐵人賽

DAY 4
0

嗨嗨又是我,前兩天的熱身不知道大家有沒有好好舒展筋骨了,今天要進入重頭戲—類別,想當年我理解這個花了蠻多時間的orz。在介紹類別前我想先介紹一個我覺得很方便的技巧,生成式。

生成式(generator)

生成式的美妙在於可以只使用一行程式碼來生成一個可能需要迴圈才能生成的串列,字典等,如果今天想生成一個串列然後元素為0~99的話,除了直接定義以外(太花時間了),也可以用迴圈定義,如下:

list1=[]
for i in range(100):
    list1.append(i)

不過這樣還是有點冗長,不過使用了生成式後就可以降低程式的複雜度,保持介面的整潔,生成式的語法為[元素 for i in 可迭代物件],具體如下:list1=[i for i in range(100)]

簡單來說就是把迴圈放在串列中,而這個方式也有更多應用,例如生成全是0或者某些特定元素的串列:list1=[0 for i in range(100)]這個生成式就會生出長度100元素全為0的串列,元素也可以是另一個生成式,概念有點像巢狀迴圈,例如list1=[[i for i in range(3)] for j in range(4)],此生程式也是先處理[i for i in range(3)],結果為[0,1,2]而這個串列會成為元素再生成四組,所以結果就會變成[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]],這樣各位有理解嗎,生成式還有很多應用,期待各位也能自行發掘更高階的應用喔!那事不宜遲,馬上進入今日的重頭戲,如果被生成式搞到精神不濟的話,請先拿杯咖啡,等等會需要稍微用心喔。

類別(class)

在第二天使用type查看資料型態會發現整數型態回傳結果為<class 'int'>,這個class就是一個類別,那如何自定義類別也很簡單,使用class Myclass:就好了類別名稱通常有個不成文的潛規則就是首字大寫,不過沒有硬性規定。

class Myclass:
    def __init__(self,name='小明',blood='B'):
        self.name=name #定義類別屬性
        self.blood=blood #定義類別屬性
    def check(self): #定義類別方法
        print(f'name:{self.name},blood:{self.blood}') #建立類別物件

如範例所示,通常類別中的變數會稱為類別的屬性,副程式會稱為類別的方法,屬性跟方法都供給類別物件使用,為物件導向程式設計的基礎概念,然後通常會定義def __init__(self):方法,此方法為呼叫此類別後會自動執行的方法,即為針對類別初始化的概念。呼叫類別就可以直接在主程式宣告物件。

a=Myclass()
b=Myclass(name='小美',blood='A')

a.check() #name:小明,blood:B
b.check() #name:小美,blood:A

可以看到a與b都為Myclass物件,當物件使用了check方法後就可以分別列印出物件屬性的資料

私有屬性、方法(類別封裝)

為了保護程式等原因,也常常使用類別封裝來讓類別外部無法使用私有屬性、方法,只能由類別內部使用,類別外部使用會引發錯誤。私有屬性、方法的定義只要在名字前加兩個下底線__就可以囉。

class Mathclass:
    def __init__(self,x,y):
        self.__a=1
        self.x=x
        self.y=y
    def __pow(self):
        return (self.x**self.y)
    def print_result(self):
        print(self.__pow())
    def print_a(self):
        print(self.__a)

a=Mathclass(x=2,y=4)
a.print_result() #16
a.print_a() #1

可以看到如果要print私有屬性__a的話,只能透過其他方法去實現,如果直接在類別外部使用的話會引發錯誤

class Mathclass:
    def __init__(self,x,y):
        self.__a=1
        self.x=x
        self.y=y
    def __pow(self):
        return (self.x**self.y)
    def print_result(self):
        print(self.__pow())
    def print_a(self):
        print(self.__a)

a=Mathclass(x=2,y=4)
print(a.__a) #AttributeError: 'Mathclass' object has no attribute '__a'
a.__pow() #AttributeError: 'Mathclass' object has no attribute '__pow'

如上圖,可以看到會引發AttributeError,所以要注意私有屬性及方法千萬不能在類別外使用!

類別繼承

通常如果要建立新的類別,但功能包含原有類別的話,可以使用繼承,通常新的類別被稱為子類別,而被繼承的類別稱為父類別,子類別可以使用所有父類別的公用屬性跟方法(私有屬性跟方法還是不能被使用,就算是繼承了類別也一樣),類別的繼承方式為class 子類別(父類別):。例如一個成績設定的程式,學生只可以查看成績,而老師除了可以查看成績以外還可以修改成績等,那就可以定義一個學生類別,方法為查看成績,老師類別繼承學生類別,除了查看成績還可以新增成績

class Student:
    def __init__(self,name):
        self.name=name
        self.score=None
    def check(self):
        print(self.name, self.score)
class Teacher(Student):
    def update(self,score,student):
        student.score = score

s=Student(name='小明')
t=Teacher(name='小明') #更改小明的成績
t.update(score=50,student=s)
t.check() #小明 None
s.check() #小明 50

這邊可以看到,首先建立了一個學生:小明,他的成績預設為空值(None),要等到老師物件針對小明去更新成績(t.update()),小明跟老師才可以查看成績(check()),也可以看到類別Teacher沒有定義方法check還是可以使用父類別的check()方法,不過就算繼承了Student類別,Teacher類別也同樣可以定義方法check(),此時稱為覆寫方法,當Teacher類別使用了check()後會優先執行本身的check()。

結語

類別在實際撰寫上可能都會遇到一些困難,不過經過時間的累積後,開發的速度就會變快很多,類別同時也是python中最最最重要的概念,務必熟悉,更多說明可看底下參考網頁。而生成式也是python中相當實用的功能,那python的基礎介紹就到這邊啦,其他細節礙於篇幅無法好好介紹,有興趣的話很多前輩們也都有更詳細的說明,可以多多爬文,多學習。接下來明天起會開始簡單介紹numpy模組~請好好期待吧!

參考資料、連結

https://docs.python.org/zh-tw/3/tutorial/classes.html


上一篇
D3:python入門(2/3)
下一篇
D5:資料科學入門!numpy基礎(1/2)
系列文
高中生也可以!利用強化學習讓機器人動起來!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言