繁体   English   中英

设置类变量的Python装饰器

[英]Python decorator which set class variable

我有一个代码,它获取FooBar中所有函数的FooBar以及函数在其参数消息上支持的正则表达式:

functionList = []

def notify(RegExpression):
    def _notify(function):
        functionList.append((RegExpression, function))

        return function

    return _notify

class FooBar:
    @notify(".*")
    def everything(self, message):
        pass

        @notify("(\w+):.*")
    def reply(self, message):
        pass

for foo in functionList:
    print("%s => %s" % foo)

我想做类似的事情,但将函数列表和它们的参数作为类变量放入类中。 当存在更多像FooBar这样的类时,它可以防止出现问题。 每个类都应该有自己的列表。

def notify(RegExpression):
    # ???

class FooBar:
    functionList = []

    @notify(".*")
    def everything(self, message):
        pass

        @notify("(\w+):.*")
    def reply(self, message):
        pass

for foo in FooBar.functionList:
    print("%s => %s" % foo)

什么投入notify()

直接使用函数装饰器执行此操作是不可能的,因为您需要访问当前正在定义的类,并且此类尚不存在。 一种解决方案是使装饰器只将正则表达式存储为方法的属性,并具有在基类上收集这些方法的功能:

def notify(regex):
    def decorate(func):
        func.regex = regex
        return func
    return decorate

class Baz(object):
    @property
    def function_list(self):
        for attr in dir(self):
            obj = getattr(self, attr)
            if callable(obj) and hasattr(obj, "regex"):
                yield obj

class FooBar(Baz):
    @notify(".*")
    def everything(self, message):
        pass

    @notify("(\w+):.*")
    def reply(self, message):
        pass

for foo in FooBar().function_list:
    print("%s => %s" % (foo.regex, foo))

notify被调用时, Foobar类甚至还不存在。 因此,你不能只使用装饰器。

你可以做的是用装饰器标记函数,并在定义类后收集它们。 您可以使用元类或类装饰器来执行此操作:

import inspect
def notify(regex):
    def mark( func ):
        func.regex = regex
        return func
    return mark

def collect( cls ):
    cls.functionList=[]
    for name, func in inspect.getmembers(cls, inspect.ismethod):
        if hasattr(func, 'regex'):
            cls.functionList.append(func)
    return cls

@collect
class FooBar(object):

    @notify(".*")
    def everything(self, message):
        pass

    @notify("(\w+):.*")
    def reply(self, message):
        pass

for foo in FooBar.functionList:
     print("%s => %s" % (foo.regex, foo))

无论如何我写了它,所以我可能只是发布了第三个选项。 它使用元类来收集函数:

def notify(regex):
    def mark( func ):
        func.regex = regex
        return func
    return mark

class RegexBase(object):
    class __metaclass__(type):
        """ creates a list of functions with a `regex` attribute 
            and stores it on the class as `functionList`
        """
        def __new__(cls, name, bases, attr):
            fl = []
            for obj in attr.itervalues():
                    if hasattr(obj, 'regex'):
                        fl.append(obj)
            attr['functionList'] = fl
            return type.__new__(cls, name, bases, attr)


class FooBar(RegexBase):

    @notify(".*")
    def everything(self, message):
        pass

    @notify("(\w+):.*")
    def reply(self, message):
        pass

for foo in FooBar.functionList:
     print("%s => %s" % (foo.regex, foo))

我想在一个线程中将所有选项放在一起很好。

这是Jochen Ritzel为Python 3更新答案。

def notify(regex):
    def mark( func ):
        func.regex = regex
        return func
    return mark


class Meta(type):
    """ creates a list of functions with a `regex` attribute 
        and stores it on the class as `functionList`
    """
    def __new__(cls, name, bases, attr):
        fl = []
        for obj in attr.values():
                if hasattr(obj, 'regex'):
                    fl.append(obj)
        attr['functionList'] = fl
        return type.__new__(cls, name, bases, attr)

class RegexBase(object, metaclass=Meta):
  pass


class FooBar(RegexBase):
    @notify(".*")
    def everything(self, message):
        pass

    @notify("(\w+):.*")
    def reply(self, message):
        pass


for foo in FooBar.functionList:
     print("%s => %s" % (foo.regex, foo))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM