Try   HackMD

Python的物件與類別

Python以物件(object)的方式看待、處理資料

Python是一種物件導向程式語言,從資料、變數到函式,都被視為「物件」(Object)來處理,物件包含以下元素

  • 名稱:用來稱呼這個物件
  • 資料型態: 設定物件的用途
  • 唯一的id: 用來區別不同物件
  • :真正的資料內容
  • 參考計數: 追蹤這物件被使用的頻率

例如宣告一個變數x = 1,在Python的設計觀點:

  • 使用者宣告了一個變數物件,賦予名稱x
  • 系統賦予一個識別用的id
  • 這個物件的資料值指定為1
  • 因為存放數值1,此物件資料型態是integer

以上是Python內建的資料型別變數物件,在這個章節中,我們將介紹,使用者怎麼自訂物件,處理客製化資料。

什麼是物件

物件(object)是一種資料型態,由屬性(Attribute)方法(Method)組成。

屬性以變數形式表示,一個物件可以包含多個屬性,例如一個多邊形物件的顏色、長度。

方法以函式來表示,一個物件可以包含多個函式,例如一個多邊形物件可以被計算面積、體積

什麼是類別

類別(Class),就是用來建立物件的方法。

你必須定義類別,來指出一個物件包含哪些屬性跟方法。

定義類別

例如你想定義一個銀行帳號的物件

  • 屬性包括帳號代碼(number)跟戶名(name)、跟餘額(balance)
  • 方法包括存款(deposit)與提款(withdraw)
    參考語法如下。
class Account: def __init__(self, number, name): self.number = number self.name = name self.balance = 0 def deposit(self, amount): #存款動作: amount代表存入金額 if amount <= 0: print('must be positive') self.balance += amount def withdraw(self, amount): #取款動作: amount代表取款金額 if amount <= self.balance: self.balance -= amount else: print('balance not enough')

從類別中建立物件

通常也被稱為實例(Instance)

延續上面的程式碼,我們建立兩個帳號資料物件,分別是:

  • Account1
    • number:S00001
    • name:AAA
  • Account2
    • number:S00002
    • name: BBB

參考程式碼如下:

class Account: def __init__(self, number, name): self.number = number self.name = name self.balance = 0 def deposit(self, amount): #存款動作: amount代表存入金額 if amount <= 0: print("Error!") self.balance += amount def withdraw(self, amount): #取款動作: amount代表取款金額 if amount <= self.balance: self.balance -= amount else: print("Error!") #建立account 1 account1 = Account("S00001", "AAA") account1.deposit(1000) #存入1000 print(account1.balance) #建立account 2 account2 = Account("S00002", "BBB") account2.deposit(2000) #存入2000 print(account2.balance)

不預先定義屬性的作法

Python允許在物件生成階段,再進行屬性的定義,例如下方例子的第16, 17行。

class Account: pass def deposit(acct, amount): if amount <= 0: raise ValueError('must be positive') acct.balance += amount def withdraw(acct, amount): if amount <= acct.balance: acct.balance -= amount else: raise RuntimeError('balance not enough') acct = Account() acct.number = '123-456-789' acct.name = 'Justin' acct.balance = 0 print(acct.number) # 123-456-789 print(acct.name) # Justin deposit(acct, 100) print(acct.balance) # 100 withdraw(acct, 50) print(acct.balance) # 50

隨堂練習

請宣告一個class CRectangle(長方形類別)

  • 它的屬性包括長width跟寬height
  • 函式是area(width, height),用來計算面積

請使用此class,生成一個長寬2x3的rectangle1物件,並且呼叫他的area方法,輸出它的面積

參考程式碼
class CRectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): area = self.width * self.height return area rectangle1 = CRectangle(2,3) rectangle1.area() print(rectangle1.area())

類別的繼承

我們從這個例子出發,有兩個class,都有drive這個方法,根據物件導向設計原則,我們應該使用繼承這個技巧,來優化程式碼,方便後續維護。

# 汽車類別 class Car: # 駕駛方法 def drive(self): print("drive method is called.") # 加速方法 def accelerate(self): print("accelerate method is called.") # 飛機類別 class Airplane: # 駕駛方法 def drive(self): print("drive method is called.") # 飛行方法 def fly(self): print("fly method is called.")

繼承作法如下,我們新增一個class Transpotation,也就是交通工工具的類別,然後讓原本的兩個classCar, Airplane繼承它,所以這兩個class都不用再實作自己的drive方法了。

# 交通工具(基底類別) class Transportation: # 建構式 def __init__(self): self.color = "white" #顏色屬性 # 駕駛方法 def drive(self): print("drive method is called.") # 汽車子類別 class Car(Transportation): # 加速方法 def accelerate(self): print("accelerate is method called.") # 飛機子類別 class Airplane(Transportation): # 飛行方法 def fly(self): print("fly method is called.")

方法覆寫(Method Overriding)

當子類別中定義了和父類別同名的方法(Method),這時候子類別的物件(Object)呼叫這個同名方法時,其中的實作內容將會覆蓋掉父類別的同名方法,這就叫做方法覆寫(Method Overriding),如下範例:

# 交通工具(基底類別) class Transportation: # 駕駛方法 def drive(self): print("Base class drive method is called.") # 汽車子類別 class Car(Transportation): # 駕駛方法 def drive(self): print("Sub class drive method is called.") car1 = Car() car1.drive()

如果我們想在子類別中執行父類別的方法時,則可以使用super()內建方法來達成,如下範例:

# 交通工具(基底類別) class Transportation: # 駕駛方法 def drive(self): print("Base class drive method is called.") # 汽車子類別 class Car(Transportation): # 駕駛方法 def drive(self): super().drive() print("Sub class drive method is called.") car1 = Car() car1.drive()

從執行結果可以看到,子類別透過super()內建方法執行父類別的drive()方法後,接著執行子類別的方法後續實作。

隨堂練習

請創造一個class,CPolygon多邊形

  • 屬性有line1, line2
  • 方法有area()計算面積

再宣告兩個class,CTriangleCRectangle,繼承CPolygon,各自實作自己的area()進行面積計算。

  • CTriangle.area(): 三角形面積公式
  • CRectangle.area(): 長方形面積公式

請使用以上兩個class,各自生成物件triangle1(2,3)rectangle1(2,3),並且使用它們的方法,計算面積並輸出。

參考程式碼
class CPolygon: def __init__(self, line1, line2): self.line1 = line1 self.line2 = line2 def area(self): print("area") class CTriangle(CPolygon): def area(self): area = (self.line1 * self.line2)/2 return area class CRectangle(CPolygon): def area(self): area = self.line1 * self.line2 return area triangle1 = CTriangle(2,3) print(triangle1.area()) rectangle1 = CRectangle(2,3) print(rectangle1.area())

類別的進階使用技巧

  • 多重繼承
  • 屬性存取
  • 聚合與組合
tags: Python程式設計入門