目标:制作一个可以修改其使用范围的装饰器。
如果有效:
class Blah(): # or perhaps class Blah(ParentClassWhichMakesThisPossible)
def one(self):
pass
@decorated
def two(self):
pass
>>> Blah.decorated
["two"]
为什么?我基本上想编写可以维护特定方法字典的类,以便我可以在每个类的基础上检索不同类型的可用方法列表。错了……
我想这样做:
class RuleClass(ParentClass):
@rule
def blah(self):
pass
@rule
def kapow(self):
pass
def shazam(self):
class OtherRuleClass(ParentClass):
@rule
def foo(self):
pass
def bar(self):
pass
>>> RuleClass.rules.keys()
["blah", "kapow"]
>>> OtherRuleClass.rules.keys()
["foo"]
最佳答案
您可以使用类装饰器(在 Python 2.6 中)或元类来做您想做的事。类装饰器版本:
def rule(f):
f.rule = True
return f
def getRules(cls):
cls.rules = {}
for attr, value in cls.__dict__.iteritems():
if getattr(value, 'rule', False):
cls.rules[attr] = value
return cls
@getRules
class RuleClass:
@rule
def foo(self):
pass
元类版本为:
def rule(f):
f.rule = True
return f
class RuleType(type):
def __init__(self, name, bases, attrs):
self.rules = {}
for attr, value in attrs.iteritems():
if getattr(value, 'rule', False):
self.rules[attr] = value
super(RuleType, self).__init__(name, bases, attrs)
class RuleBase(object):
__metaclass__ = RuleType
class RuleClass(RuleBase):
@rule
def foo(self):
pass
请注意,这两种方法都不能满足您的要求(修改调用命名空间),因为它脆弱、困难且通常是不可能的。相反,它们都通过类装饰器或元类的 __init__
方法对类进行后处理,方法是检查所有属性并填充 rules
属性。两者的区别在于,元类解决方案适用于 Python 2.5 及更早版本(降至 2.2),并且元类是继承的。使用装饰器,子类必须分别应用装饰器(如果它们想设置规则属性。)
这两种解决方案都没有考虑继承——它们在查找标记为规则的方法时不查看父类,也不查看父类的 rules
属性。如果这是您想要的,那么扩展两者都不难。
关于python装饰器修改当前范围内的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2714244/