Python私有属性通过名称改写(如__attr→_ClassName__attr)实现弱封装,并非真正不可访问;改写仅作用于类定义中双下划线开头且不以双下划线结尾的标识符,动态添加或特殊方法名(如__init__)不受影响。

Python私有属性不是真的“无法访问”,而是被名称改写(name mangling)
Python没有真正的访问控制机制,__attr 这种双下划线开头的属性会被解释器自动重命名为 _ClassName__attr。这不是加密,也不是运行时拦截,只是简单字符串拼接——类定义阶段就完成了。
所以“强制访问”这个说法不准确:你不是绕过了什么保护,只是手动拼出了改写后的名字。
- 改写只发生在类定义中直接以
__开头、且不以__结尾的标识符上(比如__value会改写,__init__不会) - 子类如果也定义同名
__attr,会各自生成不同的改写名(_SubClass__attr和_ParentClass__attr),互不影响 - 动态添加的
__attr(比如obj.__x = 1)不会被改写,因为 name mangling 只作用于类体内的定义
如何确认某个私有属性实际被改写成了什么名字
最可靠的方式是查 dir(obj) 或 obj.__dict__,而不是靠猜测。Python 不保证改写规则永远不变(虽然目前稳定),而且 IDE、调试器、help() 都可能显示原始名,造成混淆。
-
dir(obj)会列出所有属性,包括改写后的_ClassName__attr -
obj.__dict__更直接,能看到键名和值,比如{'_MyClass__data': 42} - 别依赖
obj._MyClass__data这种硬编码——一旦类名改了,或属性移到父类,代码立刻失效
用 _ClassName__attr 访问的典型风险
这种写法等于把实现细节当成公共接口在用,破坏封装意图,后续维护代价很高。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 属性可能被移除、重命名、改为 property 或描述符,而你写的
_Cls__x会静默失败或读到错误值 - 单元测试里大量使用它,会导致测试与内部结构强耦合,一次重构就得改几十个断言
- Pydantic、dataclass、ORM 模型等现代工具对双下划线字段有特殊处理,强行访问改写名可能跳过验证逻辑或触发意外副作用
- 类型检查器(如 mypy)通常不识别
_Cls__x,提示 “has no attribute” —— 这其实是提前在警告你:不该这么用
真正需要“突破封装”时的替代方案
如果你发现自己总想访问 __attr,大概率是设计信号:要么该属性本就不该私有,要么该提供受控的访问入口。
- 把
__attr改成单下划线_attr:约定为“内部使用”,既表明意图,又保留访问自由度 - 加一个只读 property:
@property def data(self): return self.__data,比暴露改写名干净得多 - 如果是测试需要,考虑在类中提供
_for_test_only_get_state()这类明确标记的方法,而非让测试直捣黄龙 - 用
getattr(obj, '_{}__data'.format(obj.__class__.__name__))动态构造?别这么做——可读性归零,且依然逃不开上述所有风险
名称改写不是锁,是贴在门上的便签:“请走正门”。撕掉便签进门容易,但门后的东西随时可能搬走。

















