【问题标题】:How to pass self attributes to a decorator?如何将自我属性传递给装饰器?
【发布时间】:2021-08-25 09:48:56
【问题描述】:

我有一个对象方法的装饰器:

def wrapper(func):
  def _wrapper(self, *a, **kw):
    print(self.foo)
    return func(self, *a, **kw)
  return _wrapper


class Bar:
  foo = 1
  
  @wrapper
  def baz(self):
    print(2)

# This works as expected :)
In [2]: Bar().baz()
1
2

我想为此添加另一层环绕以允许参数:

def wrapper(bla):
  def _wrapper(func):
    def __wrapper(self, *a, **kw):
      print(self.foo + bla)
      return func(self, *a, **kw)
    return __wrapper
  return _wrapper

class Bar:
  foo = 1

  @wrapper(1)
  def baz(self):
    print(2)

# which also works great
In [4]: Bar().baz()
2
2

现在,我想要做的是将self 属性作为包装器参数传递,即用类似这样的方式调用它

class Bar:
  def __init__(self):
    self._foo = 1

  @wrapper(self._foo)
  def baz(self):
    pass

我看到了 2 个选项:

  1. 使self._foo全局
  2. 不要传self._foo,让装饰器访问self._foo

两者都不好。 (全局可以在我不知情的情况下从另一个地方更改,并且让装饰器访问self._... 意味着装饰器知道它所操作的类) 有什么好办法吗?

【问题讨论】:

  • 将属性名作为字符串传递,调用内部时在装饰器中使用getattr()
  • 你不能那样做。当类被定义时调用装饰器,此时不可能有任何个实例。该实例只能在作为参数的内部包装器中访问。您能否就实际用例提供更多背景信息?
  • @IainShelvington 是一种技术解决方案,但是,它遇到了与我的第二个解决方案相同的问题
  • 什么问题?你只是说“两者都不好”。
  • 我不太清楚你所说的 “装饰器知道它所操作的类” 是什么意思,但 Iain 的建议是,例如@wrapper("_foo") 仅在特定包装器需要 self 具有 _foo 属性时才耦合 - 这是实际 行为 所需的耦合。

标签: python decorator


【解决方案1】:

这个例子工作得很好(你可以选择_foo_bar)并且包装器本身对Bar 及其成员一无所知:

def wrapper(bla):
  def _wrapper(func):
    def __wrapper(self, *a, **kw):
      print(getattr(self, bla))
      return func(self, *a, **kw)
    return __wrapper
  return _wrapper

class Bar:
  def __init__(self):
    self._foo = 1
    self._bar = 2

  @wrapper("_bar")  # pick _foo or _bar here
  def baz(self):
    pass


Bar().baz()

输出:2

wrapper 装饰器可以位于另一个模块中,或作为库的一部分,Bar 作为客户端将不为装饰器所知。

【讨论】:

    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 2016-04-29
    • 2021-12-09
    • 2017-11-12
    • 1970-01-01
    相关资源
    最近更新 更多