单元测试中导入前置双下划线开头的类失败如何解决
问题原因
Python 对双下划线开头、且不以双下划线结尾的标识符有默认的**名字修饰(Name Mangling)**规则,这类标识符不是传统意义上的“不可访问私有成员”,而是会被编译器自动重命名,直接用原名导入自然找不到目标。
- 如果
__MyClass是定义在其他类的内部(比如类Foo的内部类),它会被自动重命名为_Foo__MyClass - 如果
__MyClass是模块顶层定义的类,from 模块 import *的导入方式会默认跳过所有下划线开头的标识符,同时如果模块配置了__all__导出列表,双下划线开头的名字不会被自动加入列表,也会导致导入失败
另外要明确:Python 社区从来不会用双下划线给模块级的类、函数标记“私有”,双下划线的名字修饰规则只设计用来避免类继承场景下的属性名冲突,用在模块层属于误用。
解决方案
推荐方案(符合Python编码规范)
把模块级私有类的前缀从双下划线 __ 改成单下划线 _。单下划线是Python社区通用的“内部实现,不承诺对外API稳定性”的标记,不会触发任何名字重写逻辑,可以正常导入使用,完全满足单元测试的访问需求。
修改后的被测试模块(location.py)代码:
# 模块级内部类用单下划线前缀标记 class _MyClass: def __init__(self, x, y, z): self.x = x self.y = y self.z = z
测试文件代码:
import unittest from location import _MyClass class MyClassTest(unittest.TestCase): def setUp(self): self.test_class = _MyClass(x, y, z)
不推荐的兼容方案
如果一定要保留双下划线的命名,需要按名字修饰后的实际名称导入:
- 如果类是定义在名为
OuterClass的类内部,导入语句写为from location import _OuterClass__MyClass - 如果是模块顶层的双下划线类,不要用通配符导入,写全显式导入语句,同时排查是否存在模块路径错误、循环导入问题。
注意:双下划线触发的名字修饰属于Python的语法实现细节,不同Python版本可能存在调整,业务代码不要依赖这个规则做访问控制。
内容的提问来源于stack exchange,提问作者Kianmehr Ehtiatkar
相关产品推荐
相关产品推荐

