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

pytest是否会重复导入模块?类级成员为何被两次初始化

类级成员重复初始化的常见合理场景
  • 模块被重复导入:Python 导入系统允许同一物理文件以不同的模块名被加载,只要导入时的路径解析结果不同(比如混用相对导入与绝对导入、sys.path被动态修改后同文件被识别为不同模块),模块顶层代码会重新执行,类定义会重新生成,类级成员自然会被重新初始化。
  • 类定义语句被多次执行:如果类定义写在函数、循环等可被多次调用的代码块中,每次执行类定义语句都会生成全新的类对象,新类的类级成员会走初始化逻辑,和之前的类对象无关联。
  • 多进程运行场景:子进程启动后如果重新加载了模块,或者类定义是在子进程创建后才执行的,会触发类成员的二次初始化。
  • 热重载机制触发:开发、测试工具自带的热重载功能检测到文件变更后,会重新加载模块,也会导致类定义重新执行。
pytest 场景下该现象的核心原因

pytest 运行时出现该问题,绝大多数是模块重复导入导致的,常见触发逻辑如下:

  1. pytest 默认会将测试文件所在目录加入 sys.path,如果你的项目代码本身也手动将根目录加入了 sys.path,就会导致同一模块存在两种不同的导入路径,比如 from test.utils import SqlDump 和 from utils import SqlDump 会被识别为两个完全独立的模块,类会被定义两次,all 成员也会被初始化两次。
  2. 部分 pytest 插件(比如静态检查插件、覆盖率统计插件)会提前加载测试模块做分析,pytest 核心运行阶段又会重新加载一次模块,两次加载都会执行类定义代码。
  3. 自定义 pytest 钩子函数中如果手动导入了测试模块,和 pytest 自动导入的模块路径不一致也会触发重复加载。
常用修复方案

你可以根据自己的项目情况选择以下方案解决缓存丢失问题:

  • 统一项目的导入规则,全部使用基于项目根目录的绝对导入,不要混用相对导入,也不要在代码中动态修改 sys.path。
  • 在项目根目录的 pytest.ini 中固定导入模式,添加配置 import_mode = importlib 避免 pytest 自动修改 sys.path 导致的路径冲突。
  • 改用更稳定的缓存实现,避免将缓存绑定到类成员上,比如用 functools.lru_cache 实现实例缓存:
import os
import re
from functools import lru_cache

class SqlDump:
    FIXUP = re.compile(r"^(\s*CREATE SEQUENCE[^;]*)AS INTEGER([^;]*);",
                       flags=re.MULTILINE | re.IGNORECASE | re.DOTALL)
    PATH = os.path.join(os.path.dirname(__file__), 'test_data/sql_dumps/{script}.sql')

    def __init__(self, script):
        self.script = script
        self.content = self.load()

# 用模块级的缓存装饰器替代类成员缓存
@lru_cache(maxsize=None)
def get_sql_dump(script: str) -> SqlDump:
    return SqlDump(script)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 21:45:04