最近在模組開發完後需要轉換成 API 的接口服務,當時遇到一些流程問題需要解決,這篇算是探討 Python 的用法吧。
大概情境如下,模型訓練完成後,正常情況使用者會接續進行預測的動作,但也有可能因為使用者在自己的排程上暫時不需要再行預測,因此會擱置一段時間。在一段時間的靜置後,server 端會把目前 keep 住的模型消滅掉,以避免資源占用,然而當使用者要重啟服務時,重新訓練模型又會是成本,故希望重新將模型 load 回來,再直接進行預測。所以可使用 classmethod 協助我們在實例化之前把必要的資訊重載,並再行實例化。
上面大概是問題的情境,不甚清楚可以跳過,僅僅算是個紀錄,可直接看下方的內容。
使用時機
通常要使用 class 下方的 method 時(指的是我們經常使用的 instance method ),應是要先把這個 class 先給實例化(補一下實例化和把物件初始化,不確定兩者說法是否指同一件事),完成後便可應用承接了這個實例下的方法,如下面的程式:
1 | class TemperatureSimulator: |
目前開發中最常使用到的就是上述的用法。那麼 classmethod 和 staticmethod 的用法差異在哪?可來看個簡單的範例,重新建立一下概念。
流程建立
1 | class ClassA: |
首先,程式碼會在第一段先執行 ClassA 下面的程式碼,創建一個 ClassA 的 class object,同時初始化裡面的attribute 和 method。
再來到了a = ClassA()
時,才是進行實例化,這時會創建 instance object,而這個 a 會指向這個 instance object。調用a.instance_method(1)
時,因為這是一個 instance method,所以 self 參數會與剛剛的 instance object 綁定(總之這時候 a 和 self 都指向同一個地方)。
最後在ClassA.class_method(1)
被使用時,cls 則是指向了剛剛提到的 class object。而 ClassA.static_method(1)
則是永遠指向同一個記憶體位置,也就是無論創建了多少實例,它的記憶體位置是永不變的。
1 | ### 1. 實體方法已實體化後綁定 |
簡單來說,static method 的使用時機可以是在當這個方法裡不需要有 self 或是 cls 時,使用靜態方法能夠比較有效的完成工作,既不需要接收用不到的參數,另外效率也會好一些,因為 instance method,會在實際要使用它時才生成,然而 static method 不會有這個問題。
然而個人目前使用上的經驗來看,雖然感受上有點雞肋,因為常常開發時總歸大多還是使用 instance method,若遇到這種靜態的狀況,又可以以直接建立 function 的方式去進行,也就是該 function 和 class 包在同一個 module 下,可是實際上若考量到程式編寫時的架構性,當某一個方法雖然不需傳入 self 或 cls,仍然將該方法歸屬於它要服務的那個類之下,是非常有助於程式的可讀性的。
使用實例
但是在開發階段會遇到一些狀況,例如說我其實根本不需要承接實例化,可是這個方法的整體概念是要在這個 class 下進行的,那麼這個時候就可以使用 staticmethod。只要在 method 前面加上裝飾器 @staticmethod 即可,如下面的程式:
1 | class TemperatureSimulator: |
那麼在剛剛提到這次 API 遇到的問題則是 model 重啟的問題,便是藉由 classmethod 內部先行準備好要實例化時 initial 的數據,再將整個物件實例化並傳出,如下面的程式:
1 | class TemperatureSimulator: |
如同上述的內容,其實就可以清晰的區分使用時機。
reference: