###### tags: `python` # 物件導向程式設計 {%youtube Fr8wErNQkUg %} ## 專有名詞介紹 :::success **類別(class)**: * 某種事物的概念(例如:手機、電腦),說明該事物內部有什麼屬性及方法 * 定義了一件事物的抽象特點 * 藍圖、設計稿、模子 **物件(object)**: * 某種事物的成品(例如:sony手機、hp手機...,asus筆電、acer筆電...) * 實體 ::: :::success **屬性(properties)**: * 類別中的變數,我們也稱作屬性 **方法(functions)**: * 類別中的函數,我們也稱作方法 ::: :::success **定義(definition)**: * 說明該類別有什麼屬性及方法 **宣告(declaration)**: * 根據某種類別實做出一個物件 ::: :::success **公開(public)**: * 預設所有方法、屬性都是公開 * 可讓在類別或函數之外透過類別或列使用,例如:dog.name, dog.run() **私有(private)**: * 方法或屬性之前加2個底線,例如:__name * 實踐 **封裝(Encapsulation)** 概念 * 避免不小心修改到內部屬性 * 簡化使用者操作 * 隱藏內部執行步驟 ::: --- ## 層次 * **套件** > **模組** > **類別** > **方法(函數)** > **屬性(變數)** * 以上層次沒有絕對必然性 * 可以在模組或類別中直接設定屬性 * 可以在模組中直接設定方法 --- ## 注意事項 * 一定要先**定義類別**才能**宣告該類別的物件**! * 習慣上類別第一個字大寫,例如:Vehicle * 類別裡面的方法定義,第一個參數一定是self關鍵字 * 類別中可以設定子類別 * 函數中可以設定子函數 --- ## 範例一 定義一個類別叫做「車」,實作「汽車、卡車」物件 ```python= class Vehicle: doors = 4 max_speed = 160 fuel = '95' car = Vehicle() print('car.doors: ', car.doors) print('car.max_speed: ', car.max_speed) print('car.fuel: ', car.fuel) truck = Vehicle() print('truck.doors: ', truck.doors) print('truck.max_speed: ', truck.max_speed) print('truck.fuel: ', truck.fuel) ``` ## 範例二:根據參數初始化物件屬性 **\_\_init__()**: * 當透過類別實作物件時,第一時間會執行的動作 * 可設定物件屬性的初始值或預設執行哪些程序 ```python= class Vehicle: def __init__(self, doors, max_speed, fuel): self.doors = doors self.max_speed = max_speed self.fuel = fuel car = Vehicle(4, 200, '95') print('car.doors: ', car.doors) print('car.max_speed: ', car.max_speed) print('car.fuel: ', car.fuel) print() truck = Vehicle(2, 160, '柴油') print('truck.doors: ', truck.doors) print('truck.max_speed: ', truck.max_speed) print('truck.fuel: ', truck.fuel) ``` ## 觀念 類別中的函數若要指定是該類別的屬性,記得要加**self** 沒加self會被認為是函數內的變數 ```python= class Car: doors = 4 def set(self, abc): doors = abc car = Car() print(car.doors) # 4 car.set(5) print(car.doors) # 4 ``` ```python= class Car: doors = 4 def set(self, abc): self.doors = abc car = Car() print(car.doors) # 4 car.set(5) print(car.doors) # 5 ``` ## 範例三 為何需要私有屬性或方法 ```python= class Mobile: def __init__(self): self.__password = '12345' self.__alarm = None def set_alarm(self, time): if time > 9 and time < 23: self.__alarm = time return 'alarm is setting' else: return 'time is not accept' def show_password(self): name = input('input your name: ') if name == 'amos': return self.__password else: return 'your are not owner' myphone = Mobile() time = int(input('alarm time: ')) print(myphone.set_alarm(time)) ``` :::success **繼承(inheritance)** * 從既有類別(父類別)產生新類別(子類別),並擴充子類別自身的屬性與方法 * 修改父類別,底下的子類別也會被調整 * 減少重複輸入既有類別的屬性與方法 * 若子類別同名的屬性與方法會覆蓋父類別原有的屬性與方法 * 當不同子類別都會使用的屬性或方法就可以放到父類別來定義 ::: ```python= class Animal: def __init__(self, head, hand, foot): self.head = head self.hand = hand self.foot = foot def run(self): return '使用身體快速移動' class Human(Animal): def run(self): return '使用腳奔跑' class Bird(Animal): def __init__(self, head, wing, foot): self.head = head self.wing = wing self.foot = foot def run(self): return '使用雙腳奔跑' def fly(self): return '使用翅膀飛翔' animal = Animal(1, 0, 4) animal.run() human = Human(1, 2, 2) human.run() bird = Bird(1, 2, 2) bird.run() bird.fly() ``` 引用上一輩的初始化方法 ```python= class Animal: def __init__(self, head, hand, foot): self.head = head self.hand = hand self.foot = foot def run(self): return '使用身體快速移動' class Monkey(Animal): def __init__(self, head, hand, foot, food='banana'): super().__init__(head, hand, foot) # 呼叫上一輩的初始化方法 self.food = food animal = Animal(1, 0, 4) print(animal.run()) monkey = Monkey(1, 2, 2, 'fruit') print(monkey.food) print(monkey.head) print(monkey.run()) ``` :::success **鍊狀繼承(chained inheritance)** * 父類別的屬性、方法可以傳給子類別,子類別再傳給孫類別 * 修改父類別,底下的子類別、孫類別也會同時調整 ::: ```python= class Animal: def __init__(self, head, hand, foot): self.head = head self.hand = hand self.foot = foot def run(self): return '使用身體快速移動' class Human(Animal): def run(self): return '使用腳奔跑' class Bird(Animal): def __init__(self, head, wing, foot): self.head = head self.wing = wing self.foot = foot def run(self): return '使用雙腳奔跑' def fly(self): return '使用翅膀飛翔' class Penguin(Bird): def fly(self): return '無法使用翅膀飛翔' def swim(self): return '使用翅膀游泳' animal = Animal(1, 0, 4) print(animal.head, animal.hand, animal.foot) print(animal.run()) human = Human(1, 2, 2) print(human.head, human.hand, human.foot) print(human.run()) bird = Bird(1, 2, 2) print(bird.head, bird.wing, bird.foot) print(bird.run()) print(bird.fly()) penguin = Penguin(1, 2, 2) print(penguin.head, penguin.wing, penguin.foot) print(penguin.run()) print(penguin.fly()) print(penguin.swim()) ``` :::success **多重繼承(multiple inheritance)** * 子類別可以繼承多個父類別的屬性與方法 ::: ```python= class mobile: def __init__(self, phone_number): self.phone_number = phone_number def call(self, number): return '撥打' + number def receive(self, number): return '接通' + number + '來電' class PDA: def __init__(self, note): self.note = '備忘錄' def install(self, app_name): return '安裝' + app_name + '軟體' def uninstall(self, app_name): return '移除' + app_name + '軟體' class SmartPhone(mobile, PDA): pass smartPhone = SmartPhone('12345') print(smartPhone.phone_number) print(smartPhone.call('77788899944455')) print(smartPhone.receive('444551122')) print(smartPhone.install('台北等公車')) print(smartPhone.uninstall('台北等公車')) ``` ## 範例四:(註一) ```python= class Account: def __init__(self, number, name): self.number = number self.name = name self.balance = 0 def deposit(self, amount): #存款動作: amount代表存入金額 if amount <= 0: raise ValueError('must be positive') self.balance += amount def withdraw(self, amount): #取款動作: amount代表取款金額 if amount <= self.balance: self.balance -= amount else: raise RuntimeError('balance not enough') acct1 = Account('123–456–789', 'Justin') #開一個帳戶 acct1.deposit(100) acct1.withdraw(30) print(acct1.balance) #餘額是 70 ``` ## 範例: 日記軟體 軟體: - 屬性: - name:帳號 - password:密碼 - article:文章內容 - logined:是否登入 - 方法: - login:帳號登入 - logout:帳號登出 - change_pw:變更密碼 - post:更新文章內容 - read:讀取文章內容 ```python= class Software: def __init__(self): self.__name = 'admin' self.__password = 'admin' self.__article = None self.__logined = False self.__content = '' def login(self): name = input('請輸入帳號: ') password = input('請輸入密碼: ') if self.__name == name and self.__password == password: self.__logined = True print('you are login!', self.__logined) else: print('帳號或密碼錯誤,請重新輸入') def logout(self): self.__logined = False print('you are logout', self.__logined) def change_pw(self): if self.__logined: new_password = input('請輸入新密碼: ') new_password2 = input('請再輸入新密碼: ') if new_password == new_password2: self.__password = new_password print(self.__password) else: print('上下密碼不一致,請重新輸入') else: self.login() def post(self): if self.__logined: self.__content = input('請輸入文章內容: ') else: self.login() def read(self): if self.__logined: print(self.__content) else: self.login() mydictionary = Software() mydictionary.login() # mydictionary.logout() # mydictionary.change_pw() mydictionary.post() mydictionary.read() ``` --- ## 備註 1. [關於Python的類別(Class)...基本篇](https://medium.com/@weilihmen/%E9%97%9C%E6%96%BCpython%E7%9A%84%E9%A1%9E%E5%88%A5-class-%E5%9F%BA%E6%9C%AC%E7%AF%87-5468812c58f2)