python 为什么会出现“缺少必需参数:self”,当使用作为类编写的装饰器和方法时?

s5a0g9ez  于 2023-02-11  发布在  Python
关注(0)|答案(2)|浏览(202)

我用一个类编写了一个装饰器。

class to_uppercase:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        return self.func(*args, *kwargs).upper()

当我在一个函数上应用这个装饰器时,它工作了。
x一个一个一个一个x一个一个二个x
现在,当我在一个方法上应用相同的装饰器时,我得到一个错误。

class base_string:
    def __init__(self, base):
        self.base = base

    @to_uppercase
    def get_base_string(self):
        return self.base

s = base_string('word worD')
s.get_base_string()

类型错误:get_base_string()缺少1个必需的位置参数:"自我"
我错过了什么?

wgx48brx

wgx48brx1#

使用函数而不是类,但是如果你需要一个类,这里你可以做什么。

在类中添加__get__方法

当你使用一个类作为装饰器时,get_base_string现在是你的类装饰器的一个示例:

print(type(s.get_base_string))  # <class '__main__.to_uppercase'>

所以,当函数被调用时,self是对to_uppercase的引用,而你没有对s对象的引用。
来自https://stackoverflow.com/a/3296318/6251742的代码

def __get__(self, obj, obj_type):
        """Support instance methods."""
        import functools
        return functools.partial(self.__call__, obj)

通过这个方法,你可以与Python交互,获取装饰器示例,因为你是从另一个对象调用它的,所以这个对象和他的类型被发送到obj参数中的__get__方法,他的类型被发送到obj_type参数中。

s.get_base_string()
# def __get__(self, obj, obj_type)
# s go to obj, this is the self we need
# type(s) go to obj_type, we don't need that, consider renaming it "_"
# self is an instance of the decorator class

如果没有__get__方法,则被调用的函数是decorator的__call__,其中self引用decorator示例,并且没有提供装饰该方法的类的示例
因此我们需要返回一个可调用对象,其中我们修饰方法的类的示例作为第一个位置参数提供,这就是functools.partialobj(我们需要的self示例)的操作,然后这个partial将被调用。

qqrboqgw

qqrboqgw2#

外部函数的装饰器基本上工作正常

类方法的装饰器工作不正常

在装饰器中使用描述符协议将允许我们访问用self

这样的正确示例装饰的方法。

import functools
#decorater class
class to_uppercase:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        return self.func(*args, *kwargs).upper()
        
    def __get__(self, obj, objtype):
        return functools.partial(self.__call__, obj)
        

#normal class
class base_string:
    def __init__(self, base):
        self.base = base

    @to_uppercase
    def get_base_string(self):
        return self.base

s = base_string('word worD')
print(s.get_base_string())

有关详细信息或了解,请访问https://docs.python.org/3/howto/descriptor.html
更多示例Python decorator, self is mixed up
Decorating class methods - how to pass the instance to the decorator?

相关问题