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 |
一旦我测试了它,我就遇到了这样一个问题:静态方法或类方法不起作用,并且从
1 | AttributeError: 'classmethod' object has no attribute '__module__' |
是的,
有什么好的解决办法吗?
在玩了一会儿之后,我找到了一个比其他方法更好的解决方案。也许这对某人有帮助。
其基本思路如下:
- 检测属于类或静态方法的成员
- 将函数对象包装在这些方法中
- 将decorator应用于此函数
- 在
classmethod 或staticmethod 实例中包装修饰函数 - 再把它存到课堂上
代码如下:
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 |