如何在Python 3.6+中批量装饰类的所有方法?
批量给类方法添加装饰器的Python3.6+实现
方案1:类装饰器(推荐,直观灵活)
类装饰器能在类定义完成后批量修改方法,我们可以写一个通用工具,接收目标装饰器和方法匹配规则,自动给符合条件的方法套上装饰器。
通用类装饰器实现
def decorate_methods(decorator, method_check): def class_wrapper(cls): # 遍历类的所有属性,筛选出符合条件的方法 for name, method in list(cls.__dict__.items()): if callable(method) and method_check(name): setattr(cls, name, decorator(method)) return cls return class_wrapper
给类C的f1-f10应用装饰器
用这个工具处理类C,匹配规则设为“方法名以'f'开头,后缀是1-10的数字”:
def function_decorator(fn): def wrapper(*args, **kwargs): print('decorated') return fn(*args, **kwargs) return wrapper @decorate_methods(function_decorator, lambda name: name.startswith('f') and name[1:].isdigit() and 1 <= int(name[1:]) <=10) class C: def f1(self): pass def f2(self): pass # ... 省略f3到f9方法 def f10(self): pass def other_method(self): # 这个方法不会被装饰 pass
测试验证:
c = C() c.f1() # 输出: decorated c.f10() # 输出: decorated c.other_method() # 无输出
方案2:元类(底层控制类创建过程)
元类可以在类被定义的阶段就完成方法装饰,适合需要更底层控制的场景。
带参数的元类实现
class DecoratorMeta(type): def __new__(cls, name, bases, attrs, decorator=None, method_check=None): if decorator and method_check: for attr_name, attr_value in attrs.items(): if callable(attr_value) and method_check(attr_name): attrs[attr_name] = decorator(attr_value) return super().__new__(cls, name, bases, attrs)
给类C应用元类
定义类时通过metaclass参数指定元类,同时传入装饰器和匹配规则:
class C(metaclass=DecoratorMeta, decorator=function_decorator, method_check=lambda name: name.startswith('f') and name[1:].isdigit() and 1<=int(name[1:])<=10): def f1(self): pass def f10(self): pass def other_method(self): pass
子类继承父类方法的场景处理
如果父类包含通用方法,不同子类需要用不同装饰器,类装饰器的方式更灵活——给每个子类单独指定对应的装饰器即可:
示例代码
# 父类:包含通用方法f1-f10 class Parent: def f1(self): print("Parent f1") def f2(self): print("Parent f2") # ... 省略f3到f10方法 # 不同装饰器 def decorator1(fn): def wrapper(*args, **kwargs): print('--- Decorated by decorator1 ---') return fn(*args, **kwargs) return wrapper def decorator2(fn): def wrapper(*args, **kwargs): print('=== Decorated by decorator2 ===') return fn(*args, **kwargs) return wrapper # 子类1:用decorator1装饰继承的方法 @decorate_methods(decorator1, lambda name: name.startswith('f') and name[1:].isdigit() and 1<=int(name[1:])<=10) class Child1(Parent): pass # 子类2:用decorator2装饰继承的方法 @decorate_methods(decorator2, lambda name: name.startswith('f') and name[1:].isdigit() and 1<=int(name[1:])<=10) class Child2(Parent): pass
测试验证:
c1 = Child1() c1.f1() # 输出: # --- Decorated by decorator1 --- # Parent f1 c2 = Child2() c2.f2() # 输出: # === Decorated by decorator2 === # Parent f2
注:如果子类重写了父类的方法,类装饰器也会自动装饰重写后的方法,符合预期。
内容的提问来源于stack exchange,提问作者stam
相关产品推荐
相关产品推荐

