# 8_Object-Oriented Programming
---
### 物件導向 Object-oriented
##### 物件導向程式設計(Object-oriented programming, OOP)
* 類別 ( Class )
* 物件 ( Object )
* 屬性 ( Attribute )
* 方法 ( Method )
* 建構子 ( Constructor )
---
## 類別 Class
#### <font color='red'>Classes</font> provide a means of bundling data and functionality together. Creating a new class creates a new type of <font color='red'>object</font>, allowing new <font color='red'>instances</font> of that type to be made
#### Class 提供了一種結合資料與功能的手段。建立一個 class 將會新增一個<font color='red'>物件</font>的型別,並且允許建立該型別的新<font color='red'>實例</font>。
---
### 類別說明
:::info
一個抽象的概念 -- 車子,人類,大象,蛋糕 ...
* 車子 是 ... 有 ... 可以(會) ...
* 人類 是 ... 有 ... 可以(會) ...
* 大象 是 ... 有 ... 可以(會) ...
* 蛋糕 是 ... 有 ... 可以(會) ...
:::
---
### 類別 Class
:::info
車子
* 是本身具有動力得以驅動前進,具有兩輪或以上以原動機驅動
* 有廠牌,價格,動力來源,車牌號碼 ...
* 可以定速巡航,車道維持輔助 ...
:::
:::success
**類別**
**有**靜態資料 -- <font color='blue'>**屬性 (Attribute) 也就是變數**</font>
**可以**操作動作 -- <font color='blue'>**方法(Method) 也就是函式**</font>
:::
---
#### 定義類別 Class definition
```python=
class ClassName:
...
...
```
#### 建立物件 Object instantiation
```python=
object = ClassName()
```
---
#### 車子類別
```python=
# Define a car Class
class Car:
pass # nothing to do
car1 = Car() # Car instance / car object
car2 = Car() # Car instance / car object
```

---
#### 實例變數 (instance variable)
###### 每一個實例有自已的屬性資料
```python=
# Define a car Class
class Car:
pass # nothing to do
car1 = Car() # Car instance / car object
car1.brand = "Toyota"
car2 = Car() # Car instance / car object
car2.weight = 450
```

---
### \_\_init\_\_() 特別方法
###### 建立<font color=#FF6600>預設</font>實例變數
:::info
__init__(self [,... ]): constructor
self is the instance itself
:::
```python=
#initial the instace variable withr default value
def __init__(self):
self.attribute = "default value"
#initial the instace variable with user defined value
def __init__(self, attr1):
self.attribute = attr
```
---
#### 定義車子類別 + 預設實例變數
```python=
# Define a car Class
class Car:
# Constructor
def __init__(self):
# initial instance variable
self.brand = "Toyota"
```

---
#### 建立物件 車子類別 + 預設實例變數
```python=預設實例變數
class Car:
# Constructor
def __init__(self):
# initial instance variable
self.brand = "Toyota"
car1 = Car()
```

---
#### 建立物件 車子類別 + <font color=#FF6600>自訂</font>預設實例變數
```python=
class Car:
def __init__(self, brand):
self.brand = brand
car1 = Car("Toyota")
car2 = Car("Tesla")
```

---
#### 物件使用屬性 ( Access attribute)
:::info
object.attribute_name
:::
```python=
class Car:
def __init__(self, brand):
self.brand = brand
car1 = Car("Tesla")
# print car brand
print(f"car1.brand is {car1.brand}")
```
```shell
car1.brand is Tesla
```

---
#### 自訂預設實例變數的<font color=#FF6600>預設值</font>
```python=
class Car:
# sepacial method with default Toyota brand
def __init__(self, brand = "Toyota"):
# initial instance variable brand
self.brand = brand
```

---
#### 自訂預設實例變數<font color=#FF6600>使用</font>預設值產生物件
```python=
class Car:
def __init__(self, brand = "Toyota"):
self.brand = brand
car1 = Car() # No brand --> brand is Toyota
print(f"car1.brandis {car1.brand}")
```
```shell
car1.brand is Toyota
```

---
#### 自訂預設實例變數<font color=#FF6600>不使用</font>預設值產生物件
```python=
class Car:
def __init__(self, brand = "Toyota"):
self.brand = brand
car1 = Car("Tesla") # brand is Tesla
print(f"car1.brand is {car1.brand}")
```
```shell
car1.brand is Tesla
```

---
#### 實例方法 (instance method)
:::info
類別中沒有加任何裝飾詞(Decorator)的方法(Method)-也就是類別中的函式
:::
```python=
Class ClassName:
def method(self[,...]):
...
...
```
---
#### 車子類別 + 實例方法
```python=
class Car:
def __init__(self, brand = "Toyota"):
self.brand = brand
# 實例方法 instance method
def info(self):
return f"This car is {self.brand} brand)"
```

---
#### 物件使用實例方法 ( Access instance method)
:::info
object.method_name
:::
```python=
class Car:
def __init__(self, brand = "Toyota"):
self.brand = brand
def info(self):
return f"This car is {self.brand} brand"
car1 = Car("Tesla")
print(car1.info())
```
```shell
This car is Tesla brand)
```
---
##### class diagram

---
### 類別變數 Class Variable
###### 類別中直接定義的變數,所有實例共享的變數
```python=
Class ClassName:
attribute = xxx
...
...
```
---
#### 車子類別 + 類別變數
```python=
class Car:
chinese_name = "汽車" # 類別變數 class variable
def __init__(self, brand = "Toyota"):
self.brand = brand
def info(self):
return f"This {self.brand} is {self.chinese_name}"
car1 = Car("Tesla")
print(car1.info())
car2 = Car("Toyota")
print(car2.info())
```
```shell
This Tesla is 汽車
This Toyota is 汽車
```
:::danger
兩台車 chinese_name 都一樣 !!!
:::
---
##### class diagram

---
#### __str__(self) special method
###### 類別的預設方法之一,物件的字串表達形式
```
print(object) --> python call object.__str__(self)
````
```python=
class Car:
status = "Good" # class attribute
def __init__(self, brand = "Toyota"):
self.brand = brand
def __str__(self):
return f"Car class status {self.status} from __str__"
def info(self):
return f"This {self.brand} is {self.status}"
car1 = Car("Tesla")
print(car1)
```
```shell
Car class status Good from __str__
```
---
##### class diagram

---
### 類別方法 (class method)
:::info
類別中有 @classmethod 裝飾詞 (Decorator) 的方法,類別呼叫類別方法時,類別方法會傳入 cls 參數,指向類別
:::
```python=
class ClassName:
# 類別方法(Class Method)
@classmethod
def class_metho(cls):
...
...
```
---
#### 車子類別 + 類別方法
```python=
class Car:
status = "Good" # class attribute
# 類別方法(Class Method)
@classmethod
def chk_status(cls):
print("Car chk_staus is {cls.status}.")
Car.chk_status()
```
```shell
Car chk_staus is Good.
```

---
### 實例變數的存取方式
#### 車子的引擎號碼變數
```python=
class Car:
def __init__(self, engin_no = "0000-0000"):
self.engin_no = engin_no
def __str__(self):
return f"Car's engin_no is {self.engin_no}"
car1 = Car("1234-5678")
print(car1)
car1.engin_no = "2468-1357"
print(car1)
```
```shell
Car's engin_no is 1234-5678
Car's engin_no is 2468-1357
```
:::danger
引擎號碼可以改 !!!
:::
---
##### class diagram

---
#### @property 實例變數的讀取控制
:::info
@property 裝飾詞將方法轉換為只能讀取的變數
:::
```python=
class Car:
def __init__(self, engin_no = "0000-0000"):
self._engin_no = engin_no
@property # engin_no just can be read
def engin_no(self):
return self._engin_no
car1 = Car("1234-5678")
print(f"car1.engin_no {car1.engin_no}")
car1.engin_no = "2468-1357"
```
```shell
car1.engin_no 1234-5678
---------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-dd4183959b5d> in <module>
7 car1 = Car("1234-5678")
8 print(f"car1.engin_no {car1.engin_no}")
----> 9 car1.engin_no = "2468-1357"
AttributeError: can't set attribute
```
---
#### @property 實例變數的修改
:::info
@property 實例變數.setter
:::
```python=
class Car:
def __init__(self, engin_no = "0000-0000"):
self._engin_no = engin_no
@property # engin_no just can be read
def engin_no(self):
return self._engin_no
@engin_no.setter
def engin_no(self, engin_no):
self._engin_no = engin_no
car1 = Car("1234-5678")
print(f"car1.engin_no {car1.engin_no}")
car1.engin_no = "2468-1357"
print(f"car1.engin_no {car1.engin_no}")
```
```shell
car1.engin_no 1234-5678
car1.engin_no 2468-1357
```
---
##### class diagram

---
### 繼承 ( Inheritance )
:::info
If you inherit money or property, you receive it from someone who has died. <font color=#FF0FF>繼承</font>
If you inherit a characteristic or quality, you are born with it, because your parents or ancestors also had it. <font color=#FF6600>遺傳</font>
:::
---
#### Pyhton 類別繼承
:::info
繼承可使類別擁有共同的屬性或方法,將共同的屬性或方法定義在父類別(Parent Class)中,而子類別(Child Class)則透過繼承得到共同的屬性或方法
:::
---
#### 兩種車子類別
```python=
class gasoline_Car:
def __init__(self, brand, engin):
self.brand = brand
self.engin = engin
class electric_Car:
def __init__(self, brand, battery):
self.brand = brand
self.battery = battery
gcar = gasoline_Car("Totyo", "Turbo")
ecar = electric_Car("Tesla", "750kw")
```
:::danger
brand 是一樣的屬性 ...
:::
---
###### class diagram

---
#### 車子類別 父類別 -- car
:::info
車子共同的屬性 -- brand
:::
```python=
class car:
def __init__(self, brand):
self.brand = brand
car = car("Toyota")
```

---
#### 類別繼承
```python=
class child_class(parent_class):
#super() is parent class
...
```
---
###### gasoline_Car 繼承 car 類別
```python=
class car:
def __init__(self, brand):
self.brand = brand
class gasoline_Car(car):
def __init__(self, brand, engin):
super().__init__(brand)
self.engin = engin
gcar = gasoline_Car("Totyo", "Turbo")
```
---

---
#### 兩種車子繼承 car 類別
```python=
class car:
def __init__(self, brand):
self.brand = brand
class gasoline_Car(car):
def __init__(self, brand, engin):
super().__init__(brand)
self.engin = engin
class electric_Car(car):
def __init__(self, brand, battery):
super().__init__(brand)
self.battery = battery
gcar = gasoline_Car("Totyo", "Turbo")
ecar = electric_Car("Tesla", "750kw")
```
---

---
#### 有兩個共同屬性
```python=
class car:
def __init__(self, brand, engin_no):
self.brand = brand
self.engin_no = engin_no
class gasoline_Car(car):
def __init__(self, brand, engin_no, engin):
super().__init__(brand, engin_no)
self.engin = engin
gcar = gasoline_Car("Totyo", "12345678", "Turbo")
```
---

---
### Operator overloading
| Operator | Method |
| :--------: | :--------: |
| + | 'object.\_\_add\_\_(self, other) |
|- |object.\_\_sub\_\_(self, other)|
|* |object.\_\_mul\_\_(self, other)|
|// |object.\_\_floordiv\_\_(self, other)|
|/ |object.\_\_div\_\_(self, other)|
|% |object.\_\_mod\_\_(self, other)|
---
###### \_\_add\_\_() example
```python=
class MyTime:
def __init__(self, h=0, m=0):
self.hour = h
self.min = m
def __add__(self, other):
nhour = self.hour+other.hour
nmin = self.min+other.min
if nmin >= 60:
nhour = nhour + 1
nmin -= 60
if nhour >= 24:
nhour -= 24
return MyTime(nhour, nmin)
def __str__(self):
return f"{self.hour:02} : {self.min:02}"
time1 = MyTime(22, 40)
time2 = MyTime(2, 30)
time3 = time1 + time2
print(f"{time1} + {time2} = {time3}")
```
```shell
22 : 40 + 02 : 30 = 01 : 10
```
---

{"title":"8_Object-Oriented Programming","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"theme\":\"dark\"}","description":"類別 ( Class )","contributors":"[{\"id\":\"019bf104-4218-46a1-bd5c-bae805b784e6\",\"add\":49614,\"del\":38066}]"}