# Python 類別的定義與使用 - Class Attributes
###### tags: `python`
[參考課程](https://www.brilliantcode.net/761/python-3-6-class/?cli_action=1599055378.214)
[參考影音課程](https://www.youtube.com/watch?v=uPKgQ3FoVtY)
物件導向的三大特性:封裝、繼承、多型
> Class繼承、多型、封裝、建構子、變數、父類別的屬性/方法
* 語法
```python=
class FirstClass: #定義類別
"""My first class in python."""
str = "Apple" #定義變數
def fun(self): # 在類別內的函數都至少要傳入參數self
return "Hello world."
my_obj = FirstClass() # 宣告一個類別為FirstClass的物件
print(my_obj.str) # 使用物件的公開變數
print(my_obj.fun()) # 使用物件的公開函數
```
定義類別
說明:類別(class)下可以有變數屬性、函式屬性
用法:
(1)類別與類別屬性 (類別名稱.屬性名稱)
(2)類別與實體物件、實體屬性 (實體物件名稱.實體屬性名稱)
---
1. 建構子
參數固定放入self,透過self來操作實體物件,建立實體物件時,不必特別寫self
```python=
def __init__(self, 其他參數):
```
>Python不支援多建構子(multi constructor),但是可以透過預設值的方式來達成
```python=
def __init__(self, para1=”para1預設值”, para2=”para2預設值2″):
```
上述方法即可以有3種宣告方式
>使用類別自己的變數、函數都須要加上『 self.變數名稱 』才能使用
範例1:
```python=
class Point:
def __init__(self):
self.x = 3
self.y = 4
def show(self): #self一定要寫,代表實體物件本身
print(self.x,self.y)
def distance(self,targetX,targetY):
return ((self.x-targetX)**2)+((self.y-targetY))
#建立實體物件
#此實體物件包含x和y兩個實體屬性
p=Point(1,5) #1放入x,5放入y
print(p.x+p.y)
p.show()#呼叫實體方法/函式
p.distance(0,0)#計算座標3,4和坐標0,0的距離
```
範例2:
```python=
class FirstClass:
"""My first class in python."""
str1 = "Apple"
str2 = "IBM"
def __init__(self, str1="參數1", str2="參數2"):
self.str1 = str1
self.str2 = str2
def fun(self):
return "Hello world."
my_obj = FirstClass()
print(my_obj.str1)
print(my_obj.str2)
print("===分隔線===")
my_obj2 = FirstClass("我是參數1")
print(my_obj2.str1)
print(my_obj2.str2)
print("===分隔線===")
my_obj3 = FirstClass("我是參數1", "我是參數2")
print(my_obj3.str1)
print(my_obj3.str2)
```
印出:
>參數1
參數2
===分隔線===
我是參數1
參數2
===分隔線===
我是參數1
我是參數2
---
2. 繼承
語法:
```python=
class 類別名稱(父類別):
```
範例:
```python=
class Car:
wheels_number = 4 # 輪胎數量
car_doors = 4 # 車門數量
passengers = 4 # 乘客數量
def __init__(self, wheels_number=4, car_doors=4, passengers=4):
self.wheels_number = wheels_number
self.car_doors = car_doors
self.passengers = passengers
# SUV也是一種車子,所以繼承Car
class SUV(Car):
brand_name = "" # 品牌名稱
air_bag = 2 # 安全氣囊數
sunroof = True # 是否擁有天窗
def __init__(self, wheels_number, car_doors, passengers, brand_name="", air_bag=2, sunroof=False):
super().__init__(wheels_number, car_doors, passengers)
self.brand_name = brand_name
self.air_bag = air_bag
self.sunroof = sunroof
def getDetails(self):
print("==== Details ====")
print("Brand:", self.brand_name)
print("Wheels number:", self.wheels_number) # 可直接呼叫父類別的變數(屬性)
print("Doors number:", self.car_doors) # 可直接呼叫父類別的變數(屬性)
print("Air-bags number:", self.air_bag)
print("Sunroof:", self.sunroof)
print("=================")
# 宣告一台Toyota RAV的休旅車(SUV)
toyota_rav = SUV(4, 5, 5, "Toyota RAV", 4, True)
toyota_rav.getDetails()
# 宣告一台BMW X5的休旅車
bmw_x5 = SUV(4, 5, 5, "BMW X5", 6, True)
bmw_x5.getDetails()
```
---
3. 多型
>不同型態的物件,定義相同的操作介面,由於被呼叫者 (Callee) 有著相同的介面,呼叫者並不用指定特別型別,只需針對介面進行操作。
>定義兩種繼承Car的類別(SUV, Bus),同時也直接覆載(overwrite)父類別已經定義的方法
撰寫方法:直接在子類別中覆載覆類別的方法即可
```python=
class Car:
# wheels_number:輪胎數量, car_doors:車門數量, passengers:乘客數量
def __init__(self, wheels_number=4, car_doors=4, passengers=4):
self.wheels_number = wheels_number
self.car_doors = car_doors
self.passengers = passengers
def drive(self):
print("Drive a car.")
# SUV也是一種車子,所以繼承Car
class SUV(Car):
# brand_name:品牌名稱, air_bag:安全氣囊數, sunroof:是否擁有天窗
def __init__(self, wheels_number, car_doors, passengers, brand_name="", air_bag=2, sunroof=False):
super().__init__(wheels_number, car_doors, passengers)
self.brand_name = brand_name
self.air_bag = air_bag
self.sunroof = sunroof
# 覆寫父類別的drive
def drive(self):
print("Drive this {0} to my vacation.".format(self.brand_name))
def getDetails(self):
print("==== Details ====")
print("Brand:", self.brand_name)
print("Wheels number:", self.wheels_number) # 可直接呼叫父類別的變數(屬性)
print("Doors number:", self.car_doors) # 可直接呼叫父類別的變數(屬性)
print("Air-bags number:", self.air_bag)
print("Sunroof:", self.sunroof)
print("=================")
# Bus也是一種車子,所以繼承Car
class Bus(Car):
# brand_name:品牌名稱, air_bag:安全氣囊數, sunroof:是否擁有天窗
def __init__(self, wheels_number, car_doors, passengers, brand_name="", air_bag=0):
super().__init__(wheels_number, car_doors, passengers)
self.brand_name = brand_name
self.air_bag = air_bag
# 覆寫父類別的drive
def drive(self):
print("Take this {0} to my vacation.".format(self.brand_name))
def getDetails(self):
print("==== Details ====")
print("Brand:", self.brand_name)
print("Wheels number:", self.wheels_number) # 可直接呼叫父類別的變數(屬性)
print("Doors number:", self.car_doors) # 可直接呼叫父類別的變數(屬性)
print("Air-bags number:", self.air_bag)
print("=================")
# 宣告一台Toyota RAV的休旅車(SUV)
toyota_rav = SUV(4, 5, 5, "Toyota RAV", 4, True)
# 宣告一台BMW X5的休旅車
bmw_x5 = SUV(4, 5, 5, "BMW X5", 6, True)
# 宣告一台Volvo Bus的巴士
volvo_bus = Bus(4, 3, 50, "Volvo Bus", 0)
# 分別呼叫各種車輛的drive()方法
def letsDrive(cars):
for car in cars:
car.drive()
letsDrive([toyota_rav, bmw_x5, volvo_bus])
```