類別 class 讓程式維護擴展更簡單!

類別與物件的概念

Python 理財的初學者隨著程式越寫越多,應該會越來越常碰到幾種情況:

「啊!這個之前寫過,複製貼過來好了」這時候通常第一個會想到要使用的是定義 def 函數,來解決重複使用同一段程式碼的狀況。對 def 不熟的讀者可以先看之前的文章:(這裡放上 def 文章連結)

然後隨著 def 越來越多、程式越來越複雜,「物件導向」的開發方式是一種常見的做法,在 Python 主軸就是圍繞在 class 類別和物件的概念了!

「物件」是什麼呢?舉個最簡單的例子,我們在模擬或是回測的時候要假設一個虛擬的帳戶。這個帳戶就像「存摺」一樣,保存了每筆買賣和轉帳紀錄,如果要計算某段期間的損益,從存摺中查看就能算出來。

在這個情況,定義一個帳戶的類別似乎是個不錯的主意!因為,如果你正在模擬把兩支策略運行在各自的帳戶,但又想要綜合檢驗投資成效,只要用類別 class 定義「存摺」的範本,然後用這個範本創造兩本「存摺物件」,就可以讓整個程式的邏輯變得更清晰易懂。

於是,我們接下來就用這個例子來做 class 的解說吧!

Class 入門

這個例子裡,我們定義了一個 class 叫做 Account。


class Account:
    def __init__(self, balance: float = 0.0, password: str = ""):
        self.balance = balance
        self.position = {}
        self.__password = password
        
        self.log = []

    def deposit(self, amount: float):
        self.balance += amount
        self.__save_log({"type":"deposit","amount":amount})
    def withdraw(self, amount: float):
        if self.balance >= amount:
            self.balance -= amount
            self.__save_log({"type":"withdraw","amount":amount})
        else:
            print("balance insufficient!")
    def check_password(self, pw):
        return True if pw == self.__password else False

    def __save_log(self, log):
        self.log.append(log)

首先是 def __init__ 的部分,這是在我們創造這個 class 的物件時,會直接運行的函數,概念上是在初始化這個物件。而後接續的括弧是創造物件時必須傳入的參數。程式碼撰寫方式如下:


def__init__(self, 變數名稱: 預設資料型態 = 預設值, …)

依照上面的例子,我們希望在 Account 物件被創造時,要傳入初始的帳戶餘額 balance,資料型態為 float 浮點數、預設值為 0,以及傳入初始的帳戶密碼 password,資料型態為 str 字串、預設值為 “” 空字串。

在 __init__ 初始化函數內,我們把剛剛傳入的帳戶餘額和密碼存成物件的屬性,因此可以看到變數前面加了 self.,表示我們定義了這個「帳戶」的範本,它必須有這幾個屬性。除此之外,我們還定義了一個屬性叫做 position,就像證券存摺一樣,它也管理著你的股票部位,初始值為空的字典,表示帳戶裡沒有股票持倉。

眼尖的讀者應該有一個疑惑,為什麼我要把密碼定義成 self.__password 呢?在 Python 這叫做 private 私有術性。簡單來說,從外部無法直接取用這個屬性。(其實在 Python 這有破解方法,這裡先不提)。無法直接取用是什麼意思呢?這裡舉個例子:


# 首先,創造一個物件 account(開一個帳戶)
# 初始存入 10000 元,並設密碼為 example
account = Account(10000, “example”)

# 如果想創造另一個帳戶,依樣畫葫蘆就行了
account2 = Account(100, “example_2) 

print(account.balance) # 印出結果 10000
print(account.__password) 
# 出現錯誤 AttributeError: 'Account' object has no attribute '__password'

那要如何取用呢?要透過像範例裡的 check_password 函數一樣,從內部取用。所以,這時候如果我輸入以下程式碼是沒問題的!


account.check_password("example") # 回傳值為 True

另外,能夠舉一反三的同學,應該能看出,def __save_log 也帶著私有屬性!所以我不能從外部寫入帳戶紀錄 log,只能在存款(deposit 函數)和提款(withdraw 函數)時,從內部調用它。(當然這不包括破解私有屬性的情況)

實例方法 instance method:以 self 為開頭,傳入物件

上面這些函數,都是最典型、最常用的實例方法,傳入參數第一個為 self,在創造物件後,透過物件自己去呼叫。舉例來說,我們要存入 100 元的話,應該這麼寫:


account = Account(10000, “example”) # 創造物件 
account account.deposit(100) # 存入 100 元,呼叫時只需傳入 self 之後的參數

靜態方法 staticmethod:大家都能取用的方法

另外,之前收到讀者訊問說,如果我想讓人人都能調用 class 裡面的 def,用 class 來管理,要怎麼寫?

Python 能夠實現這個情境,不過有一些小撇步要注意!我們接續著前面的例子做說明。假設我們把下面這個函數「取得系統維護時間」也定義在上面的 class Account 之中:


    @staticmethod
    def get_maintenance_time():
        return "Sunday 4:00 ~ 5:00 AM"

這時候,無論是用物件呼叫,還是不先實例化,直接用類別取用,都是沒問題的!程式碼如下:


# 以物件呼叫
account = Account(10000, “example) # 創造物件 account
print(account.get_maintenance_time()) # 印出結果: "Sunday 4:00 ~ 5:00 AM"

# 直接取用(注意 Account 是 class 名稱,開頭變成大寫了!)
print(Account.get_maintenance_time()) # 一樣能印出結果: "Sunday 4:00 ~ 5:00 AM"

class 入門先講到這邊,撰寫 Python 理財會用到的 class 並不會太深,若有需要,後續我們再補充吧!


量化通粉絲社群,定期分享實用資源
✅加入LINE匿名群組量化通QuantPass」無壓力討論與分享!
✅追蹤量化通的粉絲專頁量化通QuantPass」即時獲取實用的資源!

程式交易課程推薦
📣 Python 程式交易系列線上課程,手把手開始用程式交易打造自己的被動收入!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。