原文是stackoverflow
的一則高票回答,原文鏈接 可能之前也有人翻譯過,但是剛好自己也有疑惑,所以搬運一下,個人水平有限所以可能翻譯存在誤差,歡迎指正(如侵刪)。
盡管classmethod
和staticmethod
非常的相似,但是兩者在具體的使用上還是有着細微的差別:classmethod
必須使用類對象作為第一個參數,而staticmethod
則可以不傳遞任何參數。
讓我們通過實際的例子來看看。
樣板
讓我們假設有處理日期信息的類:
class Date(object):
day = 0
month = 0
year = 0
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
這個類很顯然可以被用來存儲某些日期信息(不考慮時區信息;讓我們假設所有的日期都用UTC
表示)
這里定義了__init__
,典型的類實例初始化方法,它作為典型的instancemethod
接受參數,其中第一個傳遞的必要參數是新建的實例本身。
類方法
有一些可以通過使用classmethod
很好解決的任務。
假設我們有很多('dd-mm-yyyy')
格式字符串的日期信息,想要把它們創建成Date
類實例。我們不得不在項目的不同地方做這些事情。
所以我們必須要做到:
- 分析得到的年月日字符串,把它們轉化成三個整形變量或者擁有三個元素的元組的變量。
- 通過傳遞這些值實例化
Date
。
得到:
day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
C++擁有重載的特性可以達到這種目的,但是Python缺乏此類特性。所以,python使用classmethod
的方式。讓我們嘗試一種另類的構造函數。
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
date2 = Date.from_string('11-09-2012')
進一步分析一下以上代碼的執行,以及它的優勢:
1.在一個地方解析日期字符串並且重復使用它。 2.做到很好的封裝(相對於把執行字符串解析作為一個單獨的函數在任何地方執行,這里使用的方法更符合
OOP
的范式) 3.cls
表示類對象,而不是類實例。這樣很酷,因為如果我們繼承Date
類,那么所有的子類也都將擁有from_string
這個方法。
靜態方法
那么staticmethod
又是什么呢?它和classmethod
非常的相似,但是不強制要求傳遞參數(但是做的事與類方法或實例方法一樣)。
讓我們來看一個使用的例子。
我們有一個日期字符串需要以某種方式驗證。這個任務與之前一樣要定義在Date
類內部,但是不要求實例化它。
靜態方法在這種情況下就非常有用。看一下下面這個代碼片段:
@staticmethod
def is_date_valid(date_as_string):
day, month, year = map(int, date_as_string_split('-'))
return day <= 31 and month <= 12 and year <= 3999
is_date = Date.is_date_valid('11-09-2012')
現在正如我們了解到的staticmethod
的使用,我們不需要訪問它所屬的類,它本質上就是一個函數,調用方式和調用函數一樣,不同的是它不關注對象和對象內部屬性。