目前,我是这样做的:
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
函数装饰某些东西,它会影响所有子类。
我想我的问题是:是否有可能在基类和子类之间没有共享的可变类字段?
答案 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() # []
不可能在类对象上具有属性(除非再次还原到元类),因此必须再次通过类方法获取装饰方法的列表。与元类解决方案相比,还有一个额外的间接层。