rap*_*ura 52 python decorator wrapper
让我说我的类有很多方法,我想在每一个方法上应用我的装饰,后来当我添加新方法时,我想要应用相同的装饰器,但我不想在方法声明之上写@mydecorator所有时间?
如果我调查的__call__
是正确的方法吗?
重要提示:以下示例似乎解决了与原始问题不同的问题.
编辑:我想以这种方式展示,这是我的问题的类似解决方案,对于任何人后来发现这个问题,使用评论中提到的mixin.
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)
Run Code Online (Sandbox Code Playgroud)
然后你可以在另一个
class Wrapmymethodsaround(WrapinMixin):
def __call__:
return super(Wrapmymethodsaround, self).__call__(hey, you, *args)
Run Code Online (Sandbox Code Playgroud)
小智 57
使用遍历类属性并装饰callables的函数来装饰类.如果你的类变量可能碰巧是可调用的,那么这可能是错误的做法,并且还会修饰嵌套类(Sven Marnach指出这一点),但通常这是一个相当简洁的解决方案.示例实现(请注意,这不会排除__init__
可能需要或可能不需要的特殊方法(等)):
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
Run Code Online (Sandbox Code Playgroud)
使用这样:
@for_all_methods(mydecorator)
class C(object):
def m1(self): pass
def m2(self, x): pass
...
Run Code Online (Sandbox Code Playgroud)
在Python 3.0和3.1中,callable
不存在.它永远存在于Python 2.x中,并且作为包装器返回到Python 3.2中isinstance(x, collections.Callable)
,因此您可以callable
在这些版本中使用它(或使用此定义您自己的替换).
Sin*_*ion 26
虽然我不喜欢在显式方法中使用神奇方法,但您可以使用元类来实现此目的.
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
Run Code Online (Sandbox Code Playgroud)
并且它的工作方式就好像每个可调用的myClass
都被装饰了一样myDecorator
>>> quux = myClass()
>>> quux.baz()
bar
Run Code Online (Sandbox Code Playgroud)
不要从死里复活,但我真的很喜欢德尔南的答案,但发现它很缺乏.
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
Run Code Online (Sandbox Code Playgroud)
编辑:修复缩进
所以你可以指定方法//属性//你不想要装饰的东西
以上答案都不适合我,因为我还想装饰继承的方法,这不是通过 using 完成的__dict__
,而且我不想用元类使事情变得过于复杂。最后,我对 Python 2 的解决方案感到满意,因为我只需要立即添加一些分析代码来测量类的所有函数使用的时间。
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
Run Code Online (Sandbox Code Playgroud)
来源(略有不同的解决方案):https : //stackoverflow.com/a/3467879/1243926 在那里您还可以看到如何为 Python 3 更改它。
正如对其他答案的评论所暗示的那样,请考虑使用inspect.getmembers(cls, inspect.isroutine)
。如果您找到了适用于 Python 2 和 Python 3 并修饰继承方法的合适解决方案,并且仍然可以在 7 行中完成,请编辑。
小智 5
您可以生成一个元类。这不会修饰继承的方法。
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
Run Code Online (Sandbox Code Playgroud)
这将生成一个元类,用指定的函数装饰所有方法。您可以通过执行以下操作在 Python 2 或 3 中使用它
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
Run Code Online (Sandbox Code Playgroud)