python decorator来修改当前scop中的变量

2024-10-01 09:29:34 发布

您现在位置:Python中文网/ 问答频道 /正文

目标:创建一个decorator,它可以修改它所使用的范围。在

如果有效:

class Blah(): # or perhaps class Blah(ParentClassWhichMakesThisPossible)

    def one(self):
        pass

    @decorated
    def two(self):
        pass

>>> Blah.decorated
["two"]

为什么?本质上,我想编写一些类来维护方法的特定字典,这样我就可以在每个类的基础上检索不同类型的可用方法的列表。呃。。。。。在

我想这样做:

^{pr2}$

Tags: or方法self目标defdecoratorpassone
2条回答

问题是,在调用decorated修饰符时,没有对象Blah但是:类对象是在类主体完成执行之后生成的。最简单的方法是让decorated将信息存储在“其他地方”,例如函数属性,然后最后一次传递(类装饰器或元类)将这些信息重新放入所需的字典中。在

类decorator更简单,但它们不会被继承(因此它们不会来自父类),而元类则是继承的,因此如果您坚持继承,则必须是元类。最简单的方法是使用类修饰符和Q开头的“list”变体,而不是后面的“dict”变体:

import inspect

def classdecorator(aclass):
  decorated = []
  for name, value in inspect.getmembers(aclass, inspect.ismethod):
    if hasattr(value, '_decorated'):
      decorated.append(name)
      del value._decorated
  aclass.decorated = decorated
  return aclass

def decorated(afun):
  afun._decorated = True
  return afun

现在

^{pr2}$

给你在Q的第一部分中请求的Blah.decorated列表。相反,正如你在Q的第二部分中所请求的那样,构建dict只意味着在上面的代码中将decorated.append(name)改为{},当然,在类decorator中将decorated初始化为空dict而不是空列表。在

元类变体将使用元类的__init__在构建类主体之后执行基本相同的后处理元类的__init__获取与类主体相对应的dict作为其最后一个参数(但是您必须通过适当处理基类的类似dict或list来支持继承)。因此,元类方法在实践中只是比类装饰器“稍微”复杂一些,但从概念上讲,大多数人觉得要困难得多。如果需要的话,我会给出元类的所有细节,但是如果可行的话,我建议使用更简单的类装饰器。在

您可以使用类修饰符(在Python2.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

元类版本将是:

^{pr2}$

请注意,这两种方法都不能满足您的要求(修改调用的名称空间),因为它是脆弱的、困难的,而且常常是不可能的。相反,它们都通过类修饰符或元类的__init__方法对类进行后处理,方法是检查所有属性并填充rules属性。两者之间的区别在于元类解决方案在Python2.5和更早版本(下至2.2)中工作,并且元类是继承的。对于decorator,子类必须分别应用decorator(如果它们想设置rules属性)

这两种解决方案都没有考虑继承性,它们在查找标记为规则的方法时不查看父类,也不查看父类rules属性。如果这是你想要的话,你也不难做到这一点。在

相关问题 更多 >