跳至主要内容

Python Class 類別成員

這個主題是要介紹 Python Class 下的相關成員,
包含 VariablesFunctions

Class 結構下的 variables 可分為:
    class variable: 類別加變數名來取值
    instance variable(self): 類別所產生的 instance 專屬

Class 結構下的 methods 可分為:
    simple method:
    static method:
    class method:

Variables

Class 結構下的 variables 可分為:

class variable: 類別加變數名來取值,此類變數為所有 class 產生的 instance 共用。
instance variable: 類別所產生的 instance 專屬,需在建構子中先定義,資料需經由 self 來取得。

calc.Circle.py

  • class variable/static variable : PI
    • Circle.PI
  • instance variable(帶 self 修飾) : radius, code
    • self.radius
class Circle:
PI = 3.14 # class variable

def __init__(self, radius):
self.radius = radius # instance variable
self.code = None # 應先定義,並初始化為 None。不然會造成未初始化變數便使用的錯誤出現。

def assign_code(self, code):
self.code = code

def area(self):
return Circle.PI * self.radius ** 2 # 注意:變數存取方式

def display(self):
return ' %s\'s area is %d' % (self.code, self.area())

run.py

from calc.Circle import Circle

c1 = Circle(10)
c2 = Circle(20)

print(Circle.PI) # 3.14
print(c1.PI) # 3.14
print(c2.PI) # 3.14

c1.PI = 3.14159
print(c1.PI) # 3.14159, 發生同名變數遮蔽
print(c2.PI) # 3.14

Functions

Class 結構下的 Methods 可分為:
    simple method : instance bound method/實體方法
    static method:
    class method: 繼承結構下使用

Simple Method 實體方法

使用情境: 每個 Instance 處理各自行為時使用
  • 使用時需先建立 instance,又稱為 instance bound method,實體方法
  • 定義在 class 中,且第一個 argument 為 self 的方法
  • 指經由 self (即 instance) 取資料的方法

Simple Method 範例

  • 參考上方 calc.Circle.py 中的 methods

Static Method 靜態方法

使用情境: 創建工具套件時使用
  • 需以 @staticmethod 為方法標註
  • 類似 Java 中的靜態函數
  • 不需創建 instance 便可經由 class name 來呼叫使用,
  • static method 也只能使用類別的 static variable或傳入的 variables(無法使用 instance variables)。
  • Python 允許同名變數遮蔽的情境,因此 子類別可以覆寫父類別的 static method

static method/variable example

cala.Math.py

class Math:
PI = 3.14 # static variable

def __init__(self):
pass

@staticmethod #static method
def circle_area(radius):
return Math.PI * radius ** 2

run.py

from calc.Math import Math

print(Math.circle_area(10)) # static method

print(Math.PI) # static variable

Class Method 類別方法

使用情境: 繼承結構下,創建分支 工具套件時使用
  • 需以 @classmethod 為方法標註
  • class method 與 static method 幾乎相同,但 class method 通常用在繼承結構下。
  • class method 因為帶有 class type 資訊,所以可以取得 type 專屬的 static variable,或是不同繼承層級下的同名 static 變數。
  • class method 的 第一個 argument cls ,代表的是當前 動態 的 type(子類別的 Type)。
  • 注意重點:
    • class method 通常用在繼承結構
    • Python 允許繼承結構各自擁有同名變數
    • 因此可以說 class method 實現了繼承結構下,辨別同名 靜態 變數 的可能性
  • 另外,class method 也可以用來設計 Factory Method
    • class method 除了可以藉由 cls 來取得實例的方法與屬性外,也可以使用 cls 來呼叫建構子。
    • 此時 cls 等同於當下的 ClassName,也可想成作用類似 Java 中的 this()。

class method example:gravitational constant

galaxy.planet.py Java Style: 子類別覆寫父類別方法內容


class Planet:
GRAVITY_CONSTANT = None

def __init__(self, name='Not Define'):
self.name = name

@classmethod
def gravity(cls, mass=0.0) -> float:
return None

class Earth(Planet):
GRAVITY_CONSTANT = 9.81

@classmethod
def gravity(cls, mass: float):
return mass * cls.GRAVITY_CONSTANT

class Moon(Planet):
GRAVITY_CONSTANT = 1.62

@classmethod
def gravity(cls, mass: float):
return mass * cls.GRAVITY_CONSTANT

# def unresolved_reference (self):
# return GRAVITY_CONSTANT # unresolved_reference, 必須指名類別 Moon.GRAVITY_CONSTANT


print(Planet.gravity()) # None
print(Earth.gravity(100)) # 981.0, 以自己 Type (cls) 的引力常數計算重力
print(Moon.gravity(100)) # 162.0, 以自己 Type (cls) 的引力常數計算重力

print(Planet.GRAVITY_CONSTANT) # None
print(Earth.GRAVITY_CONSTANT) # 9.81
print(Moon.GRAVITY_CONSTANT) # 1.62

class method example 2:gravitational constant

  • planet2.py 範例等同於上方 planet1.py,注意 這邊允許父類別存與子類別的靜態變數
  • class method 定義在父類別身上,而父類別所需的子類別 靜態成員則必須事先定義

galaxy.planet2.py Pythonic Style: 父類別可存取子類別成員內容

class Planet:
GRAVITY_CONSTANT = None

def __init__(self, name='Not Define'):
self.name = name

@classmethod
def gravity(cls, mass=None) -> float:
if mass is None:
return None
return mass * cls.GRAVITY_CONSTANT
# 所有子類別必須有 GRAVITY_CONSTANT 這個靜態變數

class Earth(Planet):
GRAVITY_CONSTANT = 9.81

class Moon(Planet):
GRAVITY_CONSTANT = 1.62

class method example 3: Factory Method  

在 Python 中並沒有 Multiple Constructors 的語法,
但 Python 的建構子本身提供 VarArgs 與 KwArgs 的擴充功能,可以來補足這個問題。
然而 Multiple Constructors 雖可達到以不同方式建構物件的目的,
但卻無法表達每個建構子所代表的商業意義,因此 Design Pattern 中有了 Factory Method Pattern。
Python 中 Factory Method Pattern 可以經由 @classmethod 的特性來實作。
請看下面範例:

  • 注意: 這邊使用 @classmethod 中的 type 來呼叫建構子
    • 範例中的 User 是以 ClassName 來建構 instance
    • PM 是以 cls argument 來建構 instance

role.role.py


class Role:
def __init__(self, is_pm=False, is_pg=False, is_user=False):
self.isPM = is_pm
self.isPG = is_pg
self.isUser = is_user

# 以 cls 建構 instance
@classmethod
def PM(cls):
return cls(True, False, False)

@classmethod
def PG(cls):
return cls(False, True, False)

# 也可以用 ClassName 建構 instance
@classmethod
def User(cls):
return Role(False, False, True)

# 使用工廠方法
manager = Role.PM()
programer = Role.PG()
user = Role.User()

print(manager.isPM) # true
print(manager.isPG) # false

print(user.isPM) # false
print(user.isPG) # false
print(user.isUser) # false

Factory Method 工廠方法

Summary

Method TypesSyntaxArgument
Instance Method  self
Static Method@staticmethod  
Class Method@classmethodcls