关于装饰器DRY原则的疑问:如何避免重复使用@classmethod?
如何在Python中批量标记多个方法为类方法(避免重复使用@classmethod)
原代码报错原因
Python的装饰器是针对单个方法的语法糖,@classmethod仅会修饰紧跟在它下方的方法(即示例中的more_holiness)。后面的more_luck没有被装饰,本质还是普通实例方法:当通过类直接调用时,Python不会自动将类对象作为第一个参数传入(只有被@classmethod/@staticmethod修饰的方法才具备自动绑定逻辑),因此会提示缺少cls参数。
无需重复@classmethod的解决方案
方案1:自定义类装饰器批量转换
编写一个类装饰器,可指定目标方法名,或按命名规则自动将方法转为类方法:
指定方法名版本
def classmethods(*method_names): def decorator(cls): for name in method_names: method = getattr(cls, name) setattr(cls, name, classmethod(method)) return cls return decorator @classmethodethods('more_holiness', 'more_luck') class Cat: holiness = 100 luck = 100 def more_holiness(cls): cls.holiness += 1 def more_luck(cls): cls.luck += 1 Cat.more_holiness() print(Cat.holiness) # 输出101 Cat.more_luck() print(Cat.luck) # 输出101
按命名规则自动转换版本
如果想统一处理符合命名规则的方法(比如以more_开头),可以修改装饰器逻辑:
def auto_classmethods(prefix): def decorator(cls): for name, method in cls.__dict__.items(): if callable(method) and name.startswith(prefix): setattr(cls, name, classmethod(method)) return cls return decorator @auto_classmethods('more_') class Cat: holiness = 100 luck = 100 def more_holiness(cls): cls.holiness += 1 def more_luck(cls): cls.luck += 1
方案2:使用元类批量处理
元类可以控制类的创建流程,在类定义完成后自动将指定方法转为类方法:
class ClassMethodMeta(type): def __new__(cls, name, bases, attrs): # 遍历类属性,将符合命名规则的方法转为类方法 for attr_name, attr_value in attrs.items(): if callable(attr_value) and attr_name.startswith('more_'): attrs[attr_name] = classmethod(attr_value) return super().__new__(cls, name, bases, attrs) class Cat(metaclass=ClassMethodMeta): holiness = 100 luck = 100 def more_holiness(cls): cls.holiness += 1 def more_luck(cls): cls.luck += 1
注意事项
- 批量转换的方式虽然减少了重复代码,但可读性可能不如直接使用
@classmethod直观,团队协作时需确保所有人理解转换规则。 - 需保证目标方法的第一个参数是
cls,否则批量转换后会引发参数不匹配的错误。
内容的提问来源于stack exchange,提问作者onimushawarlord
相关产品推荐
相关产品推荐

