Python 面向物件 - @classmethod & @staticmethod
阿新 • • 發佈:2018-11-08
@classmethod和@staticmethod很像,但他們的使用場景並不一樣。
- 類內部普通的方法,都是以self作為第一個引數,代表著通過例項呼叫時,將例項的作用域傳入方法內;
- @classmethod以cls作為第一個引數,代表將類本身的作用域傳入。無論通過類來呼叫,還是通過類的例項呼叫,預設傳入的第一個引數都將是類本身
- @staticmethod不需要傳入預設引數,類似於一個普通的函式
來通過例項瞭解它們的使用場景:
假設我們需要建立一個名為Date的類,用於儲存 年/月/日 三個資料
class Date(object):
def __init__(self, year=0, month=0, day=0):
self.year = year
self.month = month
self.day = day
@property
def time(self):
return "{year}-{month}-{day}".format(
year=self.year,
month=self.month,
day=self.day
)
上述程式碼建立了Date類,該類會在初始化時設定day/month/year屬性,並且通過property設定了一個getter,可以在例項化之後,通過time獲取儲存的時間
date = Date('2016', '11', '09')
date.time # 2016-11-09
但如果我們想改變屬性傳入的方式呢?畢竟,在初始化時就要傳入年/月/日三個屬性還是很煩人的。能否找到一個方法,在不改變現有介面和方法的情況下,可以通過傳入2016-11-09這樣的字串來建立一個Date例項?
你可能會想到這樣的方法:
date_string = '2016-11-09'
year, month, day = map(str, date_string.split('-'))
date = Date(year, month, day)
但不夠好:
- 在類外額外多寫了一個方法,每次還得格式化以後獲取引數
- 這個方法也只跟Date類有關
- 沒有解決傳入引數過多的問題
此時就可以利用@classmethod,在類的內部新建一個格式化字串,並返回類的例項的方法:
# 在 Date 內新增一個 classmethod
@classmethod
def from_string(cls, string):
year, month, day = map(str, string.split('-'))
# 在 classmethod 內可以通過 cls 來呼叫到類的方法,甚至建立例項
date = cls(year, month, day)
return date
這樣,我們就可以通過Date類來呼叫from_string方法建立例項,並且不侵略、修改舊的例項化方式:
date = Date.from_string('2016-11-09')
# 舊的例項化方式仍可以使用
date_old = Date('2016', '11', '09')
好處:
- 在@classmethod內,可以通過cls引數,獲取到跟外部呼叫類時一樣的便利
- 可以在其中進一步封裝該方法,提高複用性
- 更加符合面向物件的程式設計方式
而@staticmethod,因為其本身類似於普通的函式,所以可以把和這個類相關的 helper 方法作為@staticmethod,放在類裡,然後直接通過類來呼叫這個方法。
# 在 Date 內新增一個 staticmethod
@staticmethod
def is_month_validate(month):
return int(month) <= 12 and int(month) >= 1
將與日期相關的輔助類函式作為@staticmethod方法放在Date類內後,可以通過類來呼叫這些方法:
month = '08'
if not Date.is_month_validate(month):
print('{} is a validate month number'.format(month))