在类中创建一个可以访问(当前)类本身的装饰器

时间:2009-07-15 06:58:15

标签: python inheritance class decorator

目前,我是这样做的:

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字段。现在我有一个hackish解决方案,最初将其设置为None,然后在功能装饰时检查它,但这只能以一种方式工作。换句话说,如果我继承Eggs然后用Eggs.decorate函数装饰某些东西,它会影响所有子类。

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

3 个答案:

答案 0 :(得分: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 # []

答案 1 :(得分:0)

我很确定你做不到。我想过用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...>]

答案 2 :(得分:0)

不是我有任何反对元类的东西,但你也可以在没有它们的情况下解决它:

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() # []

不可能在类对象上具有属性(除非再次还原到元类),因此必须再次通过类方法获取装饰方法的列表。与元类解决方案相比,还有一个额外的间接层。