【问题标题】:Using decorator in class method and populate variable在类方法中使用装饰器并填充变量
【发布时间】:2018-02-28 16:21:17
【问题描述】:

我正在编写一些代码,并且我有一个字典,其中键是任何字符串,值是函数。然后我遍历字典中的每个键并调用函数,如下所示:

class SomeClass:

    dictionary = {}

    # Not sure how to use this decorator function
    def decorator(key):
        def wrapper(funct):
            self.dictionary[key] = funct
            return funct
        return wrapper


    @decorator("some_val1")
    def function_1(self):
       ...

    @decorator("some_val2")
    def function_2(self):
       ...

    @decorator("some_val3")
    def function_3(self):
       ...

    def execute_all_functions(self):
        for key, _ in self.dictionary.items():
            self.dictionary[key]()


if __name__ == "__main__":
    sclass = SomeClass()
    sclass.execute_all_functions()

所以这应该填充dictionary

{
   "some_val1": function_1(),
   "some_val2": function_2(),
   "some_val3": function_3()
}

我收到了这个错误

self.dictionary[key] = funct
NameError: name 'self' is not defined

我怎么能做到这一点。帮助表示赞赏。

【问题讨论】:

  • 您是否尝试将self, 添加到类中decoratorwrapper 的定义中? def decorator(self,key):, def wrapper(self,funct):

标签: python python-3.x


【解决方案1】:

我认为这是不可能的。

首先你应该阅读这个:https://docs.python.org/3.3/howto/descriptor.html,了解函数与方法的区别。

在您的代码中,键等于方法的self

def decorator(key):
    def wrapper(funct):
        self.dictionary[key] = funct
        return funct
    return wrapper

如果你想使用一个类的属性,你应该参考cls。正确的代码可能是:

@classmethod
def decorator(cls, key):
    def wrapper(funct):
        self.dictionary[key] = funct
        return funct
    return wrapper

假设你想更新一个类属性,你必须有cls 引用。我已经尝试了下面的代码,使decorator_maker 成为一个类方法。

class SomeClass:

    dictionary = {}

    @classmethod
    def decorator_maker(cls, key):
        print(cls, key)
        def decorator(funct):
            cls.dictionary[key] = funct
            return funct
        return decorator

    @decorator_maker("some_val1")
    def function_1(self):
       ...

    @decorator_maker("some_val2")
    def function_2(self):
       ...

    @decorator_maker("some_val3")
    def function_3(self):
       ...

    def execute_all_functions(self):
        for key, _ in self.dictionary.items():
            self.dictionary[key]()

您将收到类似TypeError: 'classmethod' object is not callable 的错误。与此问题相同:'classmethod' object is not callable。 AKA,在定义类之前,您不能调用类方法。

所以你可能想在课堂之外制作装饰器。但出于同样的原因,在 classmethod 之前,您无法获得 cls 的引用。 method 也是类的一个属性,你不能在定义另一个属性的同时动态改变一个属性。见Python class method run when another method is invoked

如果你把dictionary移到课堂外会更容易。

【讨论】:

    【解决方案2】:

    functools.wraps 可能有用。在下面的简单示例中,没有wraps,装饰器将无法正常工作。

    from functools import wraps
    
    class SomeClass:
        var = 1
    
        @wraps
        def decorator(self, fn):
            return fn
    
        @decorator
        def return_value(self):
            print(self.var)
            return self.var
    
    
    if __name__ == "__main__":
        sclass = SomeClass()
        sclass.return_value()
    

    【讨论】:

    • 我认为我遇到的问题是在装饰器中访问dictionary,而当我运行execute_all_functions 时,dictionary 仍然是空的。所以看起来dictionary 变量永远不会更新
    • 问题似乎是你的装饰器看不到类变量,即self无法识别。
    • 我认为关键是让你的装饰器有一个cls 变量。昨晚试过了,还是不行:(
    猜你喜欢
    • 2014-01-14
    • 2020-01-11
    • 2022-09-29
    • 2014-08-15
    • 2020-07-23
    • 1970-01-01
    • 2022-01-16
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多