【问题标题】:Injecting class properties via decorators通过装饰器注入类属性
【发布时间】:2026-02-08 11:10:01
【问题描述】:

我有一大堆 Django 测试用例,它们使用 setUp 方法来初始化一些在众多测试中使用的属性,它们的构造方式和相互依赖的方式是我想从测试用例中移出的逻辑,并且重用

def setUp(self):
    self.property_1 = ##some logic
    ...

我想将这些重写为一些方便的包装器,可以通过简单的继承或装饰器注入到类中,例如

@with_property_1(x=1, y=2)
def setUp(self):
    ...


def with_property_1(**model_kwargs):
    def wrapper(f):
        def wrapped(*args, **kwargs):
            self = args[0]
            self.property_1 = ## logic
            f(*args, **kwargs)
        return wrapped
    return wrapper

但问题在于 PyCharm 无法识别这些实例属性的存在,因为 TestCase 类中的任何内容都不会设置它们。有没有另一种方法可以很好地实现这一点,或者有一种方法可以哄 PyCharm 承认这些属性在装饰器存在的情况下是合法的?

【问题讨论】:

标签: python django pycharm decorator testcase


【解决方案1】:

免责声明:这是未经测试的。

这里的问题是 Python 不能神奇地将 self 放入装饰器的上下文中(这在任何 IDE 中都不起作用)。您可能忘记了self 是您调用每个类方法时传递给它的参数之一。因此,它存在于您的 *args 中,您可以对其进行操作。

这是我的试用代码:

def with_property_1(**model_kwargs):
  def wrapper(f):
    def wrapped(*args, **kwargs):
      for key, value in model_kwargs.items():
        setattr(args[0], key, value)
      f(*args, **kwargs)
    return wrapped
  return wrapper

解释:

  1. 遍历**model_kwargs 中的每个键/值。

  2. 修改args[0],它应该是self变量,使用setattr提供的kwargs。

  3. 使用更新后的self 变量照常调用函数。

【讨论】:

  • 我错过了我的代码中的那一行,抱歉。我已经使用 args[0] 作为类的实例。这个问题与在类本身中使用self.property_1 更相关,PyCharm 会在其中发出编译警告,因为它看不到在任何地方设置的属性