【问题标题】:Is there a way to monkey patch a class inside a module before the module body is executed in python?有没有办法在 python 中执行模块主体之前对模块内的类进行猴子修补?
【发布时间】:2022-01-16 15:12:57
【问题描述】:

我有文件main.py,其中包含以下代码:

class A:
  def __init__(self, a):
    self.a = a
  def run(self):
    return self.a+10

a = A(4)
print(a.run())

在文件test.py 中,我尝试在main.py 中修改类A 如下:

import main

class A:
  def __init__(self, a):
    self.a = a
  def run(self):
    return self.a+5 

main.A = A

不幸的是,当我从 python 解释器运行 import test 时,模块仍然打印出 14,而不是我预期的输出 9

有没有办法在模块主体执行之前对模块内的类进行猴子补丁?

【问题讨论】:

    标签: python module mocking monkeypatching


    【解决方案1】:

    这里的问题是当你imported main.py 文件时,它使用类A 的真实实现来执行代码a = A(4)。然后你的test.py 的其余部分被执行,你替换了A 引用,但为时已晚。 您可以通过添加测试来检查:

    print(__name__)                     # __main__
    print(main.__name__)                # so70731368_main
    print(A.__module__)                 # __main__
    print(main.A.__module__)            # __main__
    print(main.a.__class__.__module__)  # so70731368_main
    

    在这里,__main__ 有点令人困惑,但这就是 Python 调用您运行的第一个文件的方式(在您的情况下为 test.py)。 a 实例在 so70731368_main 模块中声明,它使用了同一模块中的 A 类,您只是在事后使用测试文件 (__main__) 中的定义更改了 A

    您需要修补同一文件中定义的两个定义(Aa)这一事实非常棘手。 unittest.mock.patch 的功能不足以修补内部导入(它会修补导入之后)。
    您不能以一种简洁明了的方式阻止a 被实例化为main.A(真实)类并被打印出来。你可以做的是patch它之后,以供以后使用,这就是你所展示的。

    直接回答您的问题:“修补”意味着将一个引用替换为另一个,因此必须已经定义了该引用。在您的示例中,它需要在类定义和类实例化之间进行修补(print 不使用真正的a),这是不受支持的。
    这个问题没有简单的解决方案。如果您可以控制main.py 文件的代码,请尝试更改它,使其在导入时不会实例化a

    【讨论】:

      猜你喜欢
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      • 2017-03-14
      • 2014-03-22
      • 2023-02-22
      • 2014-08-29
      相关资源
      最近更新 更多