7

我正在努力寻找一种减少样板装饰器的方法。我们有很多使用@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")

我的问题是:

  1. 有没有更好的方法来完成自动装饰?
  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) 
4

1 回答 1

4

我不会让我的类的用户指定一个__metaclass__属性,而是让他们从定义它的基类派生。无需不必要地暴露管道。

除此之外,看起来还不错。您的@dont_decorate函数装饰器可以通过在原始函数上设置一个属性来实现,然后您的类装饰器会检测并跳过装饰(如果存在)。

def dont_decorate(func):
    func._dont_decorate = True
    return func

然后在你的元类中,你现在有一行if callable(value):

if callable(value) and not hasttr(value, "_dont_decorate"):

顺便说一句,类是可调用的,所以如果你不想修饰内部类,你可能应该使用isinstance()而不是检查函数callable()

如果您对更明确的替代方案感兴趣,您可以看看这个最近的问题,其中有人想使用类装饰器做本质上相同的事情。不幸的是,这有点复杂,因为方法在装饰器看到它们时已经被包装了。

于 2011-11-23T16:21:23.690 回答