You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何unittest的mock.patch.start会重复执行启动补丁的函数?

Python Mock 模块加载异常问题解析

场景重现

我们有两个Python文件:

to_patch.py

from unittest.mock import patch

def patch_a_function():
    print("Patching!")
    patcher = patch("to_be_patched.function")
    patcher.start()
    print("Done patching!")

to_be_patched.py

from to_patch import patch_a_function

def function():
    pass

patch_a_function()
function()

运行命令 python -m to_be_patched 后,输出如下:

Patching!
Patching!

疑问点

  • 为何Done patching!从未被打印?
  • 为何Patching!被打印两次?

提问者补充排查信息:调用patch.start似乎会再次触发patch_a_function执行,猜测这与to_be_patched.py中导入该函数有关,但不确定函数二次执行的原因;同时也不清楚为何两次调用patch_a_function都未执行到Done patching!代码行,patcher.start()应该不会阻塞,因为程序能正常退出而非挂起。

编辑补充:看起来没人能复现Done patching!不打印的情况——这应该是本地环境的问题。

问题解析

1. Patching!打印两次的原因

这是循环导入+Mock的模块加载机制共同导致的:

  • 执行python -m to_be_patched时,Python首先加载to_be_patched模块,当执行到from to_patch import patch_a_function时,会转而加载to_patch模块。
  • to_patch模块加载完成后,回到to_be_patched继续执行顶层代码,调用patch_a_function(),打印第一次Patching!。
  • 当执行patcher.start()时,unittest.mock.patch会尝试导入目标模块to_be_patched以定位要替换的function对象。但此时to_be_patched模块尚未完成完整加载,Python会重新执行该模块的顶层代码——于是又会导入patch_a_function并再次调用,打印第二次Patching!。

2. Done patching!未打印的问题

根据补充说明,其他环境无法复现该现象,大概率是本地Python环境、unittest.mock版本差异,或者模块缓存(__pycache__文件夹)问题导致的。正常情况下两次patch_a_function调用都应该执行到print("Done patching!"),可以尝试清理模块缓存或切换干净的虚拟环境测试。


内容的提问来源于stack exchange,提问作者AmagicalFishy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:52:24