Python 内建函数列表 > Python 的内置函数 classmethod
Python 的内置函数 classmethod 是一个装饰器,用于将一个方法标记为类方法。类方法属于类本身,而不是类的实例,因此可以在不创建实例的情况下直接通过类名调用。
def classmethod(fn):
'''
把一个方法封装成类方法
:param fn: 要封装的方法
:return: 封装后的方法
'''
使用 @classmethod 装饰器来定义类方法:
class MyClass:
@classmethod
def my_class_method(cls, arg1, arg2):
# 方法实现
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) # 直接通过类调用
emp = Employee("John", 50000)
emp.set_raise_amount(1.06) # 也可以通过实例调用(但修改的是类变量)
类方法是面向对象编程中一种特殊的方法类型,它属于类本身而非类的实例对象。与普通实例方法不同,类方法在定义时需要使用@classmethod装饰器进行修饰,并且其第一个参数约定俗成命名为cls(指代类本身),而不是实例方法的self参数。
类方法的主要特点包括:
- 访问方式:可以直接通过类名调用(如ClassName.method_name()),无需创建类的实例
- 应用场景:适合处理与类相关但不依赖于特定实例的操作
- 参数特点:自动接收类对象作为第一个参数
- 权限范围:可以访问类属性,但不能直接访问实例属性
常见的使用场景包括:
- 工厂模式:创建类的替代构造方法
- 当需要根据不同的输入参数创建不同类型的对象实例时,可以使用类方法作为工厂方法
- 例如:一个图形类可以有类方法
create_circle()和create_square()来创建特定类型的图形对象 - 比直接使用构造函数更灵活,可以封装复杂的对象创建逻辑
- 类状态的修改:修改所有实例共享的类变量
- 当需要修改或访问类的全局状态时,可以使用类方法
- 例如:一个计数器类可以用类方法
increment_count()来修改所有实例共享的计数变量 - 适用于需要在整个类范围内维护和操作共享数据的情况
- 工具方法:提供与类相关但不依赖实例的实用功能
- 当需要提供与类相关但不需要实例化的功能时,可以使用类方法
- 例如:数学计算类可以提供
convert_units()这样的单位转换方法 - 日期处理类可以提供
is_leap_year()这样的静态检查方法 - 这些方法逻辑上与类相关,但不依赖于具体的实例状态
其他应用场景还包括:
- 替代构造函数(如从不同数据格式创建对象)
- 实现单例模式
- 提供类级别的配置方法
- 执行类相关的预处理或后处理操作
示例:
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) # 相当于调用Date(year, month, day)
# 直接通过类调用而不需实例化
date = Date.from_string("2023-05-15")
与静态方法的区别: 虽然静态方法(@staticmethod)也可以通过类名直接调用,但它不会自动接收类或实例作为参数(self或cls),更适合完全独立于类和实例的操作。与实例方法必须接收self参数和类方法必须接收cls参数不同,静态方法就像一个被封装在类里的普通函数,既可被类调用,也可被实例调用。
这种特性使静态方法特别适合以下场景:
- 类中需要实现但不需要访问类或实例状态的辅助功能
- 将相关功能组织在同一个命名空间下
- 不需要继承重写的工具方法
例如:
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)
# 通过类名调用
print(MathUtility.add(2, 3)) # 输出5
print(MathUtility.factorial(5)) # 输出120
# 通过实例调用
calc = MathUtility()
print(calc.add(5, 7)) # 输出12
需要注意的是,静态方法虽然方便,但过度使用会影响代码的面向对象特性。当方法确实需要访问类或实例状态时,仍应使用实例方法或类方法。