Python 內(nèi)建函數(shù)列表 > Python 的內(nèi)置函數(shù) classmethod
Python 的內(nèi)置函數(shù) classmethod 是一個裝飾器,用于將一個方法標記為類方法。類方法屬于類本身,而不是類的實例,因此可以在不創(chuàng)建實例的情況下直接通過類名調(diào)用。
def classmethod(fn):
'''
把一個方法封裝成類方法
:param fn: 要封裝的方法
:return: 封裝后的方法
'''
使用 @classmethod 裝飾器來定義類方法:
class MyClass:
@classmethod
def my_class_method(cls, arg1, arg2):
# 方法實現(xiàn)
pass
示例:
class Employee:
raise_amount = 1.04 # 類變量
def __init__(self, name, salary):
self.name = name
self.salary = salary
@classmethod
def set_raise_amount(cls, amount):
cls.raise_amount = amount # 修改類變量
# 使用
Employee.set_raise_amount(1.05) # 直接通過類調(diào)用
emp = Employee("John", 50000)
emp.set_raise_amount(1.06) # 也可以通過實例調(diào)用(但修改的是類變量)
類方法是面向?qū)ο缶幊讨幸环N特殊的方法類型,它屬于類本身而非類的實例對象。與普通實例方法不同,類方法在定義時需要使用@classmethod裝飾器進行修飾,并且其第一個參數(shù)約定俗成命名為cls(指代類本身),而不是實例方法的self參數(shù)。
類方法的主要特點包括:
- 訪問方式:可以直接通過類名調(diào)用(如ClassName.method_name()),無需創(chuàng)建類的實例
- 應(yīng)用場景:適合處理與類相關(guān)但不依賴于特定實例的操作
- 參數(shù)特點:自動接收類對象作為第一個參數(shù)
- 權(quán)限范圍:可以訪問類屬性,但不能直接訪問實例屬性
常見的使用場景包括:
-
工廠模式:創(chuàng)建類的替代構(gòu)造方法
- 當(dāng)需要根據(jù)不同的輸入?yún)?shù)創(chuàng)建不同類型的對象實例時,可以使用類方法作為工廠方法
- 例如:一個圖形類可以有類方法
create_circle()和create_square()來創(chuàng)建特定類型的圖形對象 - 比直接使用構(gòu)造函數(shù)更靈活,可以封裝復(fù)雜的對象創(chuàng)建邏輯
-
類狀態(tài)的修改:修改所有實例共享的類變量
- 當(dāng)需要修改或訪問類的全局狀態(tài)時,可以使用類方法
- 例如:一個計數(shù)器類可以用類方法
increment_count()來修改所有實例共享的計數(shù)變量 - 適用于需要在整個類范圍內(nèi)維護和操作共享數(shù)據(jù)的情況
-
工具方法:提供與類相關(guān)但不依賴實例的實用功能
- 當(dāng)需要提供與類相關(guān)但不需要實例化的功能時,可以使用類方法
- 例如:數(shù)學(xué)計算類可以提供
convert_units()這樣的單位轉(zhuǎn)換方法 - 日期處理類可以提供
is_leap_year()這樣的靜態(tài)檢查方法 - 這些方法邏輯上與類相關(guān),但不依賴于具體的實例狀態(tài)
其他應(yīng)用場景還包括:
- 替代構(gòu)造函數(shù)(如從不同數(shù)據(jù)格式創(chuàng)建對象)
- 實現(xiàn)單例模式
- 提供類級別的配置方法
- 執(zhí)行類相關(guān)的預(yù)處理或后處理操作
示例:
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_string):
year, month, day = map(int, date_string.split('-'))
return cls(year, month, day) # 相當(dāng)于調(diào)用Date(year, month, day)
# 直接通過類調(diào)用而不需實例化
date = Date.from_string("2023-05-15")
與靜態(tài)方法的區(qū)別:
雖然靜態(tài)方法(@staticmethod)也可以通過類名直接調(diào)用,但它不會自動接收類或?qū)嵗鳛閰?shù)(self或cls),更適合完全獨立于類和實例的操作。與實例方法必須接收self參數(shù)和類方法必須接收cls參數(shù)不同,靜態(tài)方法就像一個被封裝在類里的普通函數(shù),既可被類調(diào)用,也可被實例調(diào)用。
這種特性使靜態(tài)方法特別適合以下場景:
- 類中需要實現(xiàn)但不需要訪問類或?qū)嵗隣顟B(tài)的輔助功能
- 將相關(guān)功能組織在同一個命名空間下
- 不需要繼承重寫的工具方法
例如:
class MathUtility:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def factorial(n):
return 1 if n == 0 else n * MathUtility.factorial(n-1)
# 通過類名調(diào)用
print(MathUtility.add(2, 3)) # 輸出5
print(MathUtility.factorial(5)) # 輸出120
# 通過實例調(diào)用
calc = MathUtility()
print(calc.add(5, 7)) # 輸出12
需要注意的是,靜態(tài)方法雖然方便,但過度使用會影響代碼的面向?qū)ο筇匦?。?dāng)方法確實需要訪問類或?qū)嵗隣顟B(tài)時,仍應(yīng)使用實例方法或類方法。