关于python:如何修饰类或静态方法

How to decorate class or static methods

我正在编写一个泛型类decorator,它需要将decorator应用于每个方法。我的第一种方法是这样的:

1
2
3
4
5
6
7
8
9
def class_decorator(cls):
    for name, member in vars(cls).items():
        # Ignore anything that is not a method
        if not isinstance(member, (types.FunctionType, types.BuiltinFunctionType, classmethod, staticmethod)):
            continue

        setattr(cls, name, method_decorator(member))

    return cls

装饰器本身并不重要。看起来像这样:

1
2
3
4
5
6
7
def method_decorator(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        # do something
        return fn(*args, **kwargs):

    return wrapper

一旦我测试了它,我就遇到了这样一个问题:静态方法或类方法不起作用,并且从functools.wraps中产生了以下错误:

1
AttributeError: 'classmethod' object has no attribute '__module__'

是的,classmethodstaticmethods不是正常函数,甚至不是可调用函数。一般来说,如果你需要装饰一个classmethod,你先用你的装饰器,然后用classmethod装饰器,但由于这是一个类装饰器,我不能影响装饰器的顺序。

有什么好的解决办法吗?


在玩了一会儿之后,我找到了一个比其他方法更好的解决方案。也许这对某人有帮助。

其基本思路如下:

  • 检测属于类或静态方法的成员
  • 将函数对象包装在这些方法中
  • 将decorator应用于此函数
  • classmethodstaticmethod实例中包装修饰函数
  • 再把它存到课堂上

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def class_decorator(cls):
    for name, member in vars(cls).items():
        # Good old function object, just decorate it
        if isinstance(member, (types.FunctionType, types.BuiltinFunctionType)):
            setattr(cls, name, method_decorator(member))
            continue

        # Static and class methods: do the dark magic
        if isinstance(member, (classmethod, staticmethod)):
            inner_func = member.__func__
            method_type = type(member)
            decorated = method_type(method_decorator(inner_func))
            setattr(cls, name, decorated)
            continue

        # We don't care about anything else

    return cls