iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
自我挑戰組

用python學習資料結構與演算法 學習筆記系列 第 4

簡單介紹OOP (Object-Oriented Programming)

  • 分享至 

  • xImage
  •  

為了後面學習其他資料結構像是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囉!

不錯的參考資料,大家可以自己點來瞧瞧:
https://chwang12341.medium.com/%E7%B5%A6%E8%87%AA%E5%B7%B1%E7%9A%84python%E5%B0%8F%E7%AD%86%E8%A8%98-%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E8%A8%AD%E8%A8%88oop%E6%95%99%E5%AD%B8-cb04dfe96754


上一篇
Dictionaries and tuples 字典與元組
下一篇
Linked List - Singly linked list (單向鏈結串列)
系列文
用python學習資料結構與演算法 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言