Decorator -- classmethod
@classmethod 用来把类中的方法标记为 类方法:
- 会自动接收 cls(类本身),而不是实例
- 适合处理“全局于类”的逻辑
- 常用于工厂方法、配置方法、批量创建对象等
示例:
class Demo:
@classmethod
def show(cls):
print(cls)
调用:
Demo.show() # <class '__main__.Demo'>
Demo().show() # <class '__main__.Demo'>
| 方法类型 | 自动接收参数 | 典型用途 |
|---|---|---|
| 普通方法 (def method(self)) | self(实例) | 操作实例数据 |
| 类方法 (@classmethod) | cls(类) | 工厂方法、创建实例、访问类属性 |
| 静态方法 (@staticmethod) | 无 | 工具函数,与类相关但不需要访问类或实例 |
class User:
count = 0
def __init__(self):
User.count += 1
@classmethod
def get_count(cls):
return cls.count
使用:
print(User.get_count())
你创建对象时,除了 __init__,还可能需要基于不同输入创建对象,这就是工厂方法的典型场景。
例如,把 JSON 字典变成对象:
class User:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_dict(cls, data: dict):
return cls(data["name"], data["age"])
使用:
user = User.from_dict({"name": "jack", "age": 18})
class Animal:
@classmethod
def create(cls, name):
return cls(name) # 注意:这里返回的是 *子类* 的实例
class Dog(Animal):
def __init__(self, name):
self.name = name
d = Dog.create("旺财")
print(type(d)) # <class '__main__.Dog'>
若用 staticmethod,就无法自动返回子类实例。
你项目可以这样写全局配置:
class AppConfig:
ENV = "production"
@classmethod
def is_prod(cls):
return cls.ENV == "production"
使用:
if AppConfig.is_prod():
...
class UserModel(Base):
...
@classmethod
def create_many(cls, session, items: list[dict]):
objects = [cls(**item) for item in items]
session.add_all(objects)
session.commit()
return objects
class Singleton:
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
你希望不同的输入格式创建对象:
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, s: str):
y, m, d = map(int, s.split("-"))
return cls(y, m, d)
使用:
d = Date.from_string("2025-06-21")
你常用的 “stock coderename” 可以改成 classmethod,让用户可以扩展子类:
class StockCodeUtil:
prefix_map = {
"00": "sz",
"60": "sh",
}
@classmethod
def encode(cls, code: str):
for k, v in cls.prefix_map.items():
if code.startswith(k):
return code.replace(k, v, 1)
return code
@classmethod
def decode(cls, code: str):
for k, v in cls.prefix_map.items():
if code.startswith(v):
return code.replace(v, k, 1)
return code
建议使用 classmethod 的场景:
- 工厂函数
- 需要访问类属性
- 需要返回当前类或子类的实例
- 单例模式
- 批量创建对象
- 数据转换(from_dict, from_json, from_xxx)
- 环境配置、初始化逻辑
- ❌ 当需要访问实例属性时(用 self)
- ❌ 当方法完全和类无关时(用 staticmethod)
💡 使用规则:
- 需要 self -> 普通方法
- 需要 cls -> classmethod
- 都不需要 -> staticmethod