【问题标题】:Python Decorate all methods of subclass, and provide means to overridePython 装饰子类的所有方法,并提供覆盖方法
【发布时间】:2011-11-23 15:51:36
【问题描述】:

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

编辑

与下面的 cmet 之一交谈,因为 classess 是可调用的而不是做

if callable(value):

应该是:

if isinstance(value,types.FunctionType) 

【问题讨论】:

  • 显式优于隐式。除非有很多样板(每个方法有十几个重要的行),否则我会回避元类魔法。哎呀,即便如此,只要有可能,我还是更喜欢更简单的解决方案。

标签: python python-2.5


【解决方案1】:

与其让我的类的用户指定__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()来检查函数。

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

【讨论】:

  • 所以我把 meta 类放在子类中的原因是它只装饰子类的成员。如果我将 meta 放在父类中,它将装饰所有函数类型......你有一个简单的方法来检测被调用的函数是否属于子类?
  • 您可以将@dont_decorate 放在父类中的所有函数上。 :-)
  • 这很烦人 :) 我相信这就是我走到这一步的原因......我可以创建一个中间类......
  • 或者更简洁的方法:声明一个带有方法的类,然后是从该类继承并定义__metaclass__的第二个类。然后让用户从第二个类继承。
  • 是的,你在我写第二篇评论的时候写了你的“中级”评论! :-)
猜你喜欢
  • 2021-10-04
  • 2013-07-09
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2013-05-23
  • 2017-01-31
  • 1970-01-01
  • 2020-12-26
相关资源
最近更新 更多