【问题标题】:Pass instance variables to a wrapper inside a decorator class将实例变量传递给装饰器类中的包装器
【发布时间】:2021-08-22 22:58:02
【问题描述】:

在上一个问题中,有人告诉我,我可以使用getattr 方法将实例变量传递给装饰器函数。例如,在这里我应该可以将c 传递给 some_wrapper。

如果有人感兴趣,这是原始问题。 Passing instance variables to a decorator

import functools 

def some_func(
   a = False
  ,b = None
):
      def some_decorator(func):
          @functools.wraps(func)
          def some_wrapper(self, *args, **kwargs):
              c = getattr(self, 'c', None)

              ...


class MyClass:
    def __init__(self, arg, c=None):
        self.arg = arg
        self.c = c

    @some_func(a=True)    
    def foo(self, x, y):
        ...

编辑:

当 foo 被传递到装饰器时,上面允许我做的是将 c 传递给 some_wrapper。因此,如果我有另一种方法,例如:

    @some_func(a=True)    
    def bar(self, alpha, beta):
        ...

self.c 也被传递给其他实例方法,这正是我想要的。

instance = MyClass(arg, c = 'Hi')

instance.foo(arg, blarg)
instance.bar(alpha, beta)

但是,我决定另辟蹊径,将函数装饰器转换为类装饰器。即:

class SomeClass():
    def __init__(self, *args, **kwargs):
        self.a = None
        self.b = None
       
    def __get__(self, obj, objtype):
        import functools
        return functools.partial(self.__call__, obj)
                

    def __call__(self, *args, **kwargs):
        def some_wrapper(*args, **kwargs):
            c = getattr(self, 'c', None)

        ...
        self.func = args[0]
        return some_wrapper

getattr 的工作方式与我在第一个示例中显示的方式不同。我在黑暗中的猜测是,在我的第二个示例中,该函数不再作为参数传递,因此getattr(self, 'c', None) 中的self 不再引用装饰函数中的实例。

有解决办法吗?

【问题讨论】:

  • 我没有按照您希望装饰器执行的操作。你能解释一下你对装饰师的最终目标是什么,也许我可以帮忙。三层深层装饰器有点过头了。通常它们最多为 2 层。
  • @Mythalorian:当然让我修改一下问题
  • 那么你真的已经有了一个可以工作的函数装饰器,但你想将它迁移到一个类装饰器?
  • @Mythalorian 完全正确!
  • 装饰器应该将从类中获得的值注入到函数调用中,例如c现在被传递到它所装饰的函数中?

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


【解决方案1】:

为我工作:

import functools


def some_func(a=False, b=None):
    def some_decorator(func):
        @functools.wraps(func)
        def some_wrapper(self: "MyClass", *args, **kwargs):
            kwargs.pop("y")
            c = self.c
            return func(self, *args, **kwargs, y=c)
        return some_wrapper
    return some_decorator


class MyClass:
    def __init__(self, arg, c=None):
        self.arg = arg
        self.c = c

    @some_func(a=True)
    def foo(self, x, y):
        print(f"foo x={x} y={y}")


no_c = MyClass("arg")
no_c.foo(x=3, y=4)
yes_c = MyClass("blarg", c="I do")
yes_c.foo(x=3, y=4)

输出:

foo x=3 y=None
foo x=3 y=I do

【讨论】:

    猜你喜欢
    • 2021-08-20
    • 2017-11-12
    • 2013-07-05
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 2012-12-13
    • 2019-05-24
    相关资源
    最近更新 更多