【问题标题】:Creating a decorator in a class with access to the (current) class itself在可以访问(当前)类本身的类中创建装饰器
【发布时间】:2010-11-10 22:01:35
【问题描述】:

目前,我正在这样做:

class Spam(object):

    decorated = None

    @classmethod
    def decorate(cls, funct):
        if cls.decorated is None:
            cls.decorated = []
        cls.decorated.append(funct)
        return funct


class Eggs(Spam):
    pass


@Eggs.decorate
def foo():
    print "spam and eggs"


print Eggs.decorated # [<function foo at 0x...>]
print Spam.decorated # None

需要能够在子类中执行此操作,如图所示。问题是我似乎无法弄清楚如何使 decorated 字段不在实例之间共享。现在我有一个骇人听闻的解决方案,最初将其设置为None,然后在装饰函数时检查它,但这只能以一种方式工作。换句话说,如果我将Eggs 子类化,然后用Eggs.decorate 函数装饰某些东西,它会影响所有子类。

我想我的问题是:是否有可能有在基类和子类之间不共享的可变类字段?

【问题讨论】:

  • 只是出于好奇:为什么需要跟踪哪些函数已被修饰?
  • 好问题。我实际上没有,但我设计了这个场景作为这个问题的一个例子,因为这是一个简单的原因,人们需要能够访问这个类。

标签: python inheritance class decorator


【解决方案1】:

我通过使用元类解决了这个问题。感谢所有发帖的人。如果有人遇到类似问题,这是我的解决方案:

class SpamMeta(type):

    def __new__(cls, name, bases, dct):
        SpamType = type.__new__(cls, name, bases, dct)
        SpamType.decorated = []
        return SpamType


class Spam(object):

    __metaclass__ = SpamMeta

    @classmethod
    def decorate(cls, funct):
        cls.decorated.append(funct)
        return funct


class Eggs(Spam):
    pass


@Eggs.decorate
def foo():
    print "spam and eggs"


print Eggs.decorated # [<function foo at 0x...>]
print Spam.decorated # []

【讨论】:

    【解决方案2】:

    我很确定你不能。我想过用 property() 来做这个,但不幸的是,类本身的类——一个属性需要去的地方——是 ClassType 本身。

    你可以这样写你的装饰器,但它会稍微改变界面:

    class Spam(object):
        decorated = {}
    
        @classmethod
        def get_decorated_methods(cls):
            return cls.decorated.setdefault(cls, [])
    
        @classmethod
        def decorate(cls, funct):
            cls.get_decorated_methods().append(funct)
            return funct
    
    
    class Eggs(Spam):
        pass
    
    
    @Spam.decorate
    def foo_and_spam():
        print "spam"
    
    @Eggs.decorate
    def foo_and_eggs():
        print "eggs"
    
    print Eggs.get_decorated_methods() # [<function foo_and_eggs at 0x...>]
    print Spam.get_decorated_methods() # [<function foo_and_spam at 0x...>]
    

    【讨论】:

    • 我让它与使用元类完美结合。如果您对如何操作感到好奇,我发布了答案。感谢您调查,格伦。
    【解决方案3】:

    并不是说我反对元类,但没有它们你也可以解决它:

    from collections import defaultdict
    
    class Spam(object):
        _decorated = defaultdict(list)
    
        @classmethod
        def decorate(cls, func):
            cls._decorated[cls].append(func)
            return func
    
        @classmethod
        def decorated(cls):
            return cls._decorated[cls]
    
    
    class Eggs(Spam):
        pass
    
    @Eggs.decorate
    def foo():
        print "spam and eggs"
    
    print Eggs.decorated() # [<function foo at 0x...>]
    print Spam.decorated() # []
    

    不可能在类对象上拥有属性(除非您再次恢复到元类),因此必须再次通过类方法获取修饰方法的列表。与元类解决方案相比,涉及额外的间接层。

    【讨论】:

    • 是的,这似乎与格伦的做法相似。即使它适用于这个例子,它仍然不能解决我不希望在父子之间共享类字段的问题。
    猜你喜欢
    • 2011-04-11
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 2011-06-26
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    相关资源
    最近更新 更多