【问题标题】:self lost when using partial inside a decorator在装饰器中使用 partial 时自我丢失
【发布时间】:2020-04-12 23:19:05
【问题描述】:

我正在尝试从一个使用另一个类的装饰器的类中编写一个方法。问题是我需要存储在包含装饰器(ClassWithDecorator.decorator_param)的类中的信息。为了实现这一点,我使用部分注入 self 作为第一个参数,但是当我这样做时,使用装饰器的类中的 self 以某种方式“迷路了”,我最终得到了一个错误。请注意,如果我从my_decorator() 中删除partial(),则不会发生这种情况,并且“self”将正确存储在*args 中。

查看代码示例:

from functools import partial


class ClassWithDecorator:
    def __init__(self):
        self.decorator_param = "PARAM"

    def my_decorator(self, decorated_func):
        def my_callable(ClassWithDecorator_instance, *args, **kwargs):
            # Do something with decorator_param
            print(ClassWithDecorator_instance.decorator_param)
            return decorated_func(*args, **kwargs)

        return partial(my_callable, self)


decorator_instance = ClassWithDecorator()


class WillCallDecorator:
    def __init__(self):
        self.other_param = "WillCallDecorator variable"

    @decorator_instance.my_decorator
    def decorated_method(self):
        pass


WillCallDecorator().decorated_method()

我明白了

PARAM
Traceback (most recent call last):
  File "****/decorator.py", line 32, in <module>
    WillCallDecorator().decorated_method()
  File "****/decorator.py", line 12, in my_callable
    return decorated_func(*args, **kwargs)
TypeError: decorated_method() missing 1 required positional argument: 'self'

如何将WillCallDecorator()对应的self传递给decorated_method(),同时将自己类中的信息传递给my_callable()

【问题讨论】:

  • 这能回答你的问题吗? Decorators with parameters?
  • 但是为什么 partial() 会从参数中删除 self 呢?
  • 装饰器始终在需要明确接收自身作为参数的未绑定方法上工作。
  • 你为什么要使用partial?装饰器可以直接作为作用域变量访问self

标签: python python-3.x python-decorators


【解决方案1】:

看来您可能想使用partialmethod 而不是partial

来自文档:

class functools.partialmethod(func, /, *args, **keywords)

当 func 是非描述符可调用时,会动态创建适当的绑定方法。当用作方法时,它的行为类似于普通的 Python 函数:self 参数将作为第一个位置参数插入,甚至在提供给 partialmethod 构造函数的参数和关键字之前。

【讨论】:

  • 这正是我想要的,谢谢。下次我会阅读完整的官方文档
【解决方案2】:

使用你已经拥有的self 变量就简单多了。完全没有理由在这里使用partialpartialmethod

from functools import partial


class ClassWithDecorator:
    def __init__(self):
        self.decorator_param = "PARAM"

    def my_decorator(self, decorated_func):
        def my_callable(*args, **kwargs):
            # Do something with decorator_param
            print(self.decorator_param)
            return decorated_func(*args, **kwargs)

        return my_callable


decorator_instance = ClassWithDecorator()


class WillCallDecorator:
    def __init__(self):
        self.other_param = "WillCallDecorator variable"

    @decorator_instance.my_decorator
    def decorated_method(self):
        pass


WillCallDecorator().decorated_method()

此外,为了回答您的代码为何不起作用的问题,当您访问 something.decorated_method() 时,代码会检查 decorated_method 是否是一个函数,如果是,则在内部将其转换为调用 WillCallDecorator.decorated_method(something)。但是从partial 返回的值是functools.partial 对象,而不是function。所以类查找绑定不会在这里发生。

更详细地说,当something 没有属性method 并且它的类型SomethingClass 确实有属性并且属性有方法__get__ 时,something.method(arg) 等价于SomethingClass.method.__get__(something, arg),但是属性查找的全套步骤相当复杂。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-03
    • 2011-07-03
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2015-03-21
    相关资源
    最近更新 更多