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

Python构造函数可变默认参数值跨测试套件被覆盖问题求解

问题核心原因

这是Python中可变类型作为函数默认参数的固有特性,和unittest模块无关,生产环境如果保留错误写法同样会触发该问题。

原理说明

Python的函数默认参数是在函数定义阶段一次性初始化完成的,不会在每次函数调用时重新生成。当你使用列表、字典这类可变类型作为默认参数时,所有未显式传入该参数的函数调用,都会共享同一个可变对象,对该对象的修改会直接作用到默认参数本身。

对应你的场景触发逻辑

你代码中__init__方法的oldInfo={}、newInfo={}用了字典(可变类型)作为默认值,触发流程如下:

  • 定义Info类时,就生成了两个全局共享的空字典,作为oldInfo、newInfo的默认参数
  • 实例化infoA时仅传入了oldInfo参数,newInfo用默认值,因此infoA._newInfo直接指向上述全局共享的默认空字典
  • 调用infoA.combine(infoB)时,会把infoB._newInfo里的v2:2写入infoA._newInfo,也就是直接修改了全局共享的默认参数字典
  • 后续实例化Info时如果不主动传入newInfo,默认用的就是已经被修改过的这个字典,自然会拿到{'v2':2}
修复方案

将可变类型的默认参数替换为None,在函数内部初始化可变对象即可:

def __init__(self, key, *, name=None, id=None, oldInfo=None, newInfo=None,
             priority=Priority.DEFAULT):
        self._key = key    
        self._name = name
        self._id = id
        self._oldInfo = oldInfo if oldInfo is not None else {}
        self._newInfo = newInfo if newInfo is not None else {}
        self._priority = priority

        assert(not self._oldInfo or type(self._oldInfo) is dict)
        assert(not self._newInfo or type(self._newInfo) is dict)
        assert(type(self._priority) is Priority)

        self._appendix = None
生产环境风险说明

该问题并非unittest模块特有,只要你的代码运行在同一个进程上下文里,按顺序执行实例化对象→修改共享默认参数→再次实例化对象的流程,不管是测试环境还是生产环境都会100%复现。unittest只是因为所有用例在同一进程顺序执行,刚好把这个代码本身的缺陷暴露出来了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:36:03