###### 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)