How to decorate all functions of a class without typing it over and over for each method?
假设我的类有许多方法,并且我希望将decorator应用于其中的每一个方法,稍后当我添加新方法时,我希望应用相同的decorator,但我不想一直在方法声明上方编写@my decorator?
如果我调查一下
重要提示:下面的示例似乎解决了与原始问题不同的问题。
编辑:我想展示这种方式,这是一个类似于我的问题的解决方案,任何一个后来发现这个问题的家伙,使用一个在评论中提到的mixin。
1 2 3 4 5 6 7 8 9 10 11 | class WrapinMixin(object): def __call__(self, hey, you, *args): print 'entering', hey, you, repr(args) try: ret = getattr(self, hey)(you, *args) return ret except: ret = str(e) raise finally: print 'leaving', hey, repr(ret) |
然后你可以换一个
1 2 3 | class Wrapmymethodsaround(WrapinMixin): def __call__: return super(Wrapmymethodsaround, self).__call__(hey, you, *args) |
用一个遍历类属性并修饰可调用文件的函数来修饰类。如果您有可能恰好可以调用的类变量,那么这可能是错误的做法,并且还将修饰嵌套类(这归功于Sven Marnach指出的),但一般来说,这是一个相当干净和简单的解决方案。示例实施(请注意,这不会排除可能需要或可能不需要的特殊方法(
1 2 3 4 5 6 7 | def for_all_methods(decorator): def decorate(cls): for attr in cls.__dict__: # there's propably a better way to do this if callable(getattr(cls, attr)): setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate |
这样使用:
1 2 3 4 5 | @for_all_methods(mydecorator) class C(object): def m1(self): pass def m2(self, x): pass ... |
在python 3.0和3.1中,
虽然我不喜欢在使用显式方法时使用神奇的方法,但您可能会为此使用元类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def myDecorator(fn): fn.foo = 'bar' return fn class myMetaClass(type): def __new__(cls, name, bases, local): for attr in local: value = local[attr] if callable(value): local[attr] = myDecorator(value) return type.__new__(cls, name, bases, local) class myClass(object): __metaclass__ = myMetaClass def baz(self): print self.baz.foo |
它的作用就好像在
1 2 3 | >>> quux = myClass() >>> quux.baz() bar |
不是为了让死神复活,但我真的很喜欢德尔南的回答,但我发现它非常缺乏。
1 2 3 4 5 6 7 | def for_all_methods(exclude, decorator): def decorate(cls): for attr in cls.__dict__: if callable(getattr(cls, attr)) and attr not in exclude: setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate |
编辑:固定缩进
因此,您可以指定方法//属性//不希望修饰的内容
以上的答案对我来说都不起作用,因为我还想修饰继承的方法,这不是通过使用
1 2 3 4 5 6 7 | import inspect def for_all_methods(decorator): def decorate(cls): for name, fn in inspect.getmembers(cls, inspect.ismethod): setattr(cls, name, decorator(fn)) return cls return decorate |
来源(略有不同的解决方案):https://stackoverflow.com/a/3467879/1243926在这里,您还可以看到如何为python 3更改它。
正如对其他答案的评论所表明的那样,考虑使用
您可以生成一个元类。这不会修饰继承的方法。
1 2 3 4 5 6 7 8 9 10 | def decorating_meta(decorator): class DecoratingMetaclass(type): def __new__(self, class_name, bases, namespace): for key, value in list(namespace.items()): if callable(value): namespace[key] = decorator(value) return type.__new__(self, class_name, bases, namespace) return DecoratingMetaclass |
这将生成一个用指定函数修饰所有方法的元类。您可以在python 2或3中使用它,方法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def doubling_decorator(f): def decorated(*a, **kw): return f(*a, **kw) * 2 return decorated class Foo(dict): __metaclass__ = decorating_meta(doubling_decorator) def lookup(self, key): return self[key] d = Foo() d["bar"] = 5 print(d.lookup("bar")) # prints 10 |