Attaching a decorator to all functions within a class
我不需要这样做,只是想知道,有没有一种方法可以将修饰符绑定到类中的所有函数,而不是为每个函数显式地声明它。
我想它会变成一种方面,而不是一个装饰,它确实感觉有点奇怪,但在考虑时间或授权之类的事情时,它会非常整洁。
每当您考虑更改类定义时,都可以使用类修饰器或元类。例如,使用元类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import types class DecoMeta(type): def __new__(cls, name, bases, attrs): for attr_name, attr_value in attrs.iteritems(): if isinstance(attr_value, types.FunctionType): attrs[attr_name] = cls.deco(attr_value) return super(DecoMeta, cls).__new__(cls, name, bases, attrs) @classmethod def deco(cls, func): def wrapper(*args, **kwargs): print"before",func.func_name result = func(*args, **kwargs) print"after",func.func_name return result return wrapper class MyKlass(object): __metaclass__ = DecoMeta def func1(self): pass MyKlass().func1() |
输出:
1 2 | before func1 after func1 |
注意:它不会修饰staticmethod和classmethod
要做到这一点,或者对类定义进行其他修改,最干净的方法是定义一个元类。
或者,只需在类定义的末尾应用decorator:
1 2 3 4 5 6 | class Something: def foo(self): pass for name, fn in inspect.getmembers(Something): if isinstance(fn, types.UnboundMethodType): setattr(Something, name, decorator(fn)) |
对于python 3,将types.unbundMethodType替换为types.functionType。
当然,在实践中,你会更加有选择地应用你的装饰器,一旦你想装饰除一种方法以外的所有方法,你就会发现,仅仅以传统的方式使用装饰器语法更容易、更灵活。
当然,当您想要修改Python创建对象的方式时,元类是最简单的方法。这可以通过重写类的
没有必要使用
以下是您可以使用的元计算示例:
1 2 3 4 5 6 | class TheMeta(type): def __new__(cls, name, bases, namespace, **kwds): # if your decorator is a class method of the metaclass use # `my_decorator = cls.my_decorator` in order to invoke the decorator. namespace = {k: v if k.startswith('__') else my_decorator(v) for k, v in namespace.items()} return type.__new__(cls, name, bases, namespace) |
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | def my_decorator(func): def wrapper(self, arg): # You can also use *args instead of (self, arg) and pass the *args # to the function in following call. return"the value {} gets modified!!".format(func(self, arg)) return wrapper class TheMeta(type): def __new__(cls, name, bases, namespace, **kwds): # my_decorator = cls.my_decorator (if the decorator is a classmethod) namespace = {k: v if k.startswith('__') else my_decorator(v) for k, v in namespace.items()} return type.__new__(cls, name, bases, namespace) class MyClass(metaclass=TheMeta): # a = 10 def __init__(self, *args, **kwargs): self.item = args[0] self.value = kwargs['value'] def __getattr__(self, attr): return"This class hasn't provide the attribute {}.".format(attr) def myfunction_1(self, arg): return arg ** 2 def myfunction_2(self, arg): return arg ** 3 myinstance = MyClass(1, 2, value=100) print(myinstance.myfunction_1(5)) print(myinstance.myfunction_2(2)) print(myinstance.item) print(myinstance.p) |
输出:
1 2 3 4 | the value 25 gets modified!! the value 8 gets modified!! 1 This class hasn't provide the attribute p. # special method is not decorated. |
对于上述注释中的第3项,您可以取消对行
1 2 | namespace = {k: v if k.startswith('__') and not isinstance(v, types.FunctionType)\ else my_decorator(v) for k, v in namespace.items()} |
您可以重写
1 2 3 | class Eggs(object): def __getattr__(self, attr): return decorate(getattr(self, `_` + attr)) |
有一些丑陋的递归隐藏在那里,你会想保护,但这是一个开始。