為了後面學習其他資料結構像是linked list、tree等等,我們需要學一下物件導向程式設計,也就是大家耳熟能詳的OOP。很多時候,我們想要多個物件有多個類似的功能和屬性時,一個一個撰寫會讓整個程式看起來很雜亂。於是在python裡我們可以使用class來創建物件,並封裝(encapsulation)想要的功能和屬性。不同物件間,一個物件可以繼承(inheritance)其他物件的功能與屬性。而物件的實體化就叫實體(instance),可能直接看code會比較容易理解些。
這裡我們創了一個class叫Restaurant,它有屬性(attribute)meat,capacity還有一個私有屬性__topsecret,__這裡的功用,就是將屬性或是方法私有化,讓它變成instance後無法從外面叫到。
class Restaurant:
#初始化,有的叫它建構式,實體被建立的時候會呼叫的函式
#初始化時,我們要給他一個capacity的值,沒給的話,就會是預設的5
def __init__(self,capacity=5):
#屬性(attribute)
self.meat=['宮保雞丁','三杯雞','椒麻雞']
self.capacity=capacity
#把它變成class外面叫不到的屬性設成private,前面多加 __
self.__topsecret='topsecret'
def show_menu(self):
print(self.meat)
def show_cap(self):
print(f'最多坐 {self.capacity} 人')
# 把它變成private method,只有class裡面的函式能用
def __secret(self):
print('secret of the restaurant')
# waiter函式把private的都叫出來瞧瞧
def Waiter(self):
self.__secret()
print(f'Waiter also know {self.__topsecret}')
# 這裡我們用Restaurant這個物件創了一個實體(instance)叫myRes, capacity=10
myRes=Restaurant(10)
# 當然我們也可以不給capacity,就會是預設的5
myRes2=Restaurant()
myRes2.capacity
>> 5
# 我們可以試著檢查他的屬性
myRes.meat
>> ['宮保雞丁', '三杯雞', '椒麻雞']
myRes.capacity
>> 10
# 因為__topsecret已經被私有化了,因此myRes.__topsecret會讓我們得到error message
myRes.__topsecret
>> AttributeError: 'Restaurant' object has no attribute '__topsecret'
# 也可以試著叫它的方法
myRes.show_menu()
>> ['宮保雞丁', '三杯雞', '椒麻雞']
myRes.show_cap()
>> 最多坐 10 人
# 一樣我們無法叫被私有化的方法
myRes.__secret()
>> AttributeError: 'Restaurant' object has no attribute '__secret'
# 但內部的function可以使用那些被私有化的方法或屬性
myRes.Waiter()
>>secret of the restaurant
>>Waiter also know topsecret
接著我們來看看物件間的繼承(inheritance),延續剛剛的例子
class Restaurant:
def __init__(self,capacity=5):
self.meat=['宮保雞丁','三杯雞','椒麻雞']
self.capacity=capacity
self.__topsecret='topsecret'
def show_menu(self):
print(self.meat)
def show_cap(self):
print(f'最多坐 {self.capacity} 人')
def __secret(self):
print('secret of the restaurant')
def Waiter(self):
self.__secret()
print(f'Waiter also know {self.__topsecret}')
class Food_Factory:
def __init__(self):
self.processedfood=['百頁豆腐','豆包','豆皮']
self.bread=['紅豆麵包','綠豆麵包','黃豆麵包']
def cut_service(self):
print('cut cut cut')
#單一繼承的時候,可以這樣寫
class supermarket(Restaurant):
def __init__(self,capacity):
super().__init__(capacity)
#當然也是可以寫成
#class supermarket(Restaurant):
# def __init__(self,capacity):
# Restaurant.__init__(capacity)
#或者是
class supermarket2(Food_Factory):
def __init__(self):
super().__init__()
#多重繼承的時候,可以這樣寫
class mall(Food_Factory,Restaurant):
def __init__(self,capacity):
Food_Factory.__init__(self)
Restaurant.__init__(self,capacity)
# 這時候supermarket就繼承了Restaurant的功能
superM=supermarket(50)
superM.show_menu()
>> ['宮保雞丁', '三杯雞', '椒麻雞']
superM.capacity
>> 50
# supermarket2也一樣
superM2=supermarket2()
superM2.processedfood
>>['百頁豆腐', '豆包', '豆皮']
# 多重繼承的mall就繼承Food_Factory和Restaurant的功能
mymall=mall(300)
mymall.show_menu()
>>['宮保雞丁', '三杯雞', '椒麻雞']
mymall.processedfood
>>['百頁豆腐', '豆包', '豆皮']
這裡稍微介紹一下class裡常見的function,像是__str__,repr,iter,next,之後都有機會用到。首先__str__是當你要print你的instance的時候,__str__方法裡return的即是你看到東西。repr,當你直接輸入你的instance,想要看到的東西,就寫在__repr__方法裡。__iter__或是__next__常常會搭配loop一起使用,直接看程式碼可能更容易理解。
class Food_Factory:
def __init__(self,name):
self.boss='Mandy'
self.employee_number=300
self.name=name
#這裡寫直接輸入instance出來的東西
def __repr__(self):
return f'Welcome to {self.name}'
#這裡寫經print function出來的東西
def __str__(self):
return f'This is {self.name}'
Fac2=Food_Factory('Lucky_Factory')
Fac2
>> Welcome to Lucky_Factory
print(Fac2)
>> This is Lucky_Factory
class Food_Factory:
def __init__(self):
self.processedfood=['百頁豆腐','豆包','豆皮']
self.bread=['紅豆麵包','綠豆麵包','黃豆麵包']
def __iter__(self):
num=0
while num<len(self.processedfood):
yield self.processedfood[num]
num+=1
Fac3=Food_Factory()
for i in Fac3:
print(i)
>> 百頁豆腐
>> 豆包
>> 豆皮
class Food_Factory:
def __init__(self):
self.processedfood=['百頁豆腐','豆包','豆皮']
self.bread=['紅豆麵包','綠豆麵包','黃豆麵包']
self.num=-1
def __next__(self):
self.num+=1
if self.num<len(self.bread):
return self.bread[self.num]
else:
raise StopIteration
#第四個next的時候,這個instance的self.num已經超過self.bread的index了,所以不管怎麼next都會raise StopIteration
fac4=Food_Factory()
print(next(fac4))
print(next(fac4))
print(next(fac4))
print(next(fac4))
>> 紅豆麵包
>> 綠豆麵包
>> 黃豆麵包
>> StopIteration
看完了OOP,我們就可以開始接下來的linked list囉!