Python 装饰子类中的所有方法,并提供重写方式
我正在寻找一种方法来减少重复的装饰器代码。我们有很多类都使用了 @decorate 这个装饰器。例如:
class MyClass(Base):
@decorate
def fun1(self):
pass
@decorate
def fun2(self):
pass
def fun3(self):
pass
我想默认情况下这个装饰器是存在的,除非有人特别说明不需要。
我用这段代码来自动添加装饰器:
from functools import wraps
def myDecorator(func):
@wraps(func)
def decorator(self, *args, **kwargs):
try:
print 'enter'
ret = func(self, *args, **kwargs)
print 'leave'
except:
print 'exception'
ret = None
return ret
return decorator
class TestDecorateAllMeta(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 TestClass(object):
__metaclass__ = TestDecorateAllMeta
def test_print2(self, val):
print val
def test_print(self, val):
print val
c = TestClass()
c.test_print1("print 1")
c.test_print2("print 2")
我想问的问题是:
- 有没有更好的方法来实现自动添加装饰器?
- 我该如何进行覆盖?
理想情况下,我最终的解决方案应该是这样的:
class TestClass(object):
__metaclass__ = TestDecorateAllMeta
def autowrap(self):
print("Auto wrap")
@dont_decorate
def test_dont_decorate(self, val):
print val
编辑
为了回应下面的一个评论,由于类是可调用的,所以不需要这样做:
if callable(value):
应该改成:
if isinstance(value,types.FunctionType)
1 个回答
4
与其让我的类的用户自己指定一个 __metaclass__
属性,不如让他们直接从我定义的基类继承,这样就不需要让用户接触那些复杂的东西了。
除此之外,其他部分看起来不错。你的 @dont_decorate
函数装饰器可以通过在原始函数上设置一个属性来实现,这样你的类装饰器就可以检测到这个属性,如果存在就跳过装饰。
def dont_decorate(func):
func._dont_decorate = True
return func
然后在你的 metaclass 中,原本有一行 if callable(value):
,你只需要改成:
if callable(value) and not hasttr(value, "_dont_decorate"):
顺便提一下,类是可以被调用的,所以如果你不想让内部类被装饰,最好用 isinstance()
来检查函数,而不是用 callable()
。
如果你对更明确的替代方案感兴趣,可以看看 这个最近的问题,里面有人想用类装饰器做类似的事情。不幸的是,这要复杂得多,因为方法在装饰器看到它们的时候已经被包装过了。