You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何程序化给类所有方法加装饰器并跳过已有指定装饰器的方法

解决方案:给类方法批量加装饰器并跳过指定装饰的方法

嘿,这个需求我之前做缓存框架的时候刚好碰到过!Python确实没有直接暴露“查看方法上所有装饰器”的内置API,但我们可以换个思路——给not_cacheable装饰器打个自定义标记,这样就能在批量处理的时候轻松识别出哪些方法要跳过了。下面一步步来实现:

1. 给not_cacheable加个识别标记

我们可以给被not_cacheable装饰的方法附加一个自定义属性,比如_is_not_cacheable = True。这里记得用functools.wraps保留原方法的元数据,避免后续出现奇怪的问题:

import functools

def not_cacheable(func):
    # 给原始方法打标记,方便后续识别
    func._is_not_cacheable = True
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

2. 修改cacheable装饰器,检查标记并跳过

接下来调整你的类装饰器cacheable,遍历类方法时先检查这个标记,如果存在就跳过该方法。另外要注意:绑定的实例方法需要通过__func__拿到原始函数,要是有多层装饰器,还得递归找到最原始的方法(通过__wrapped__属性):

import inspect

def get_original_func(func):
    # 递归跳过所有装饰器wrapper,找到最原始的方法
    while hasattr(func, '__wrapped__'):
        func = func.__wrapped__
    return func

def cacheable(decorator):
    def decorate(cls):
        for name, member in inspect.getmembers(cls):
            # 覆盖实例方法、类方法、静态方法三种情况
            if inspect.ismethod(member):
                target_func = member.__func__
            elif inspect.isfunction(member):
                target_func = member
            else:
                continue  # 跳过非方法的属性
            
            original_func = get_original_func(target_func)
            # 如果方法带有not_cacheable标记,就跳过
            if getattr(original_func, '_is_not_cacheable', False):
                continue
            
            # 根据方法类型重新包装并替换原方法
            if isinstance(member, classmethod):
                setattr(cls, name, classmethod(decorator(target_func)))
            elif isinstance(member, staticmethod):
                setattr(cls, name, staticmethod(decorator(target_func)))
            else:
                setattr(cls, name, decorator(member))
        return cls
    return decorate

3. 完整使用示例

这里我写个带测试的完整代码,你可以直接运行验证效果:

import functools
import inspect

# 1. 定义带标记的not_cacheable装饰器
def not_cacheable(func):
    func._is_not_cacheable = True
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"👉 执行未缓存方法: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

# 2. 定义示例缓存装饰器
def my_cache_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"💾 缓存装饰器生效: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

# 3. 定义批量处理的cacheable类装饰器
def get_original_func(func):
    while hasattr(func, '__wrapped__'):
        func = func.__wrapped__
    return func

def cacheable(decorator):
    def decorate(cls):
        for name, member in inspect.getmembers(cls):
            if inspect.ismethod(member):
                target_func = member.__func__
            elif inspect.isfunction(member):
                target_func = member
            else:
                continue
            
            original_func = get_original_func(target_func)
            if getattr(original_func, '_is_not_cacheable', False):
                continue
            
            if isinstance(member, classmethod):
                setattr(cls, name, classmethod(decorator(target_func)))
            elif isinstance(member, staticmethod):
                setattr(cls, name, staticmethod(decorator(target_func)))
            else:
                setattr(cls, name, decorator(member))
        return cls
    return decorate

# 4. 测试类
@cacheable(my_cache_decorator)
class C(object):
    @not_cacheable
    def method_1(self):
        pass
    
    def method_2(self, x):
        pass
    
    @classmethod
    @not_cacheable
    def class_method(cls):
        pass
    
    @staticmethod
    def static_method():
        pass

# 运行测试
c = C()
c.method_1()          # 只会打印"👉 执行未缓存方法: method_1",不会触发缓存
c.method_2(10)        # 会打印"💾 缓存装饰器生效: method_2"
C.class_method()      # 只会打印"👉 执行未缓存方法: class_method"
C.static_method()     # 会打印"💾 缓存装饰器生效: static_method"

一些额外提示

  • 装饰器顺序:如果你的方法有多个装饰器,确保@not_cacheable是最内层的装饰器(直接贴在方法定义上),这样标记才会打在原始方法上;如果没法保证顺序,我们的get_original_func函数也能递归找到最原始的方法,不用担心。
  • 方法类型:上面的代码已经处理了实例方法、类方法、静态方法三种常见情况,覆盖了大部分场景。

内容的提问来源于stack exchange,提问作者HIT_girl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 23:32:34