点号访问私有字段失败是因为名称混淆导致字面名不存在,Python将__value重命名为_ClassName__value,点号直接查找原始名而无法匹配。

因为点号访问是按字面名查找属性,而私有字段在定义时已被 Python 自动重命名,原始名字在实例字典里根本不存在。
名称改写让原名“消失”了
Python 遇到以双下划线开头、且不以双下划线结尾的属性(如 __value),会在类定义阶段就把它改成 _ClassName__value。这个动作叫“名称混淆”(name mangling)。
- 实例的 __dict__ 里存的是改写后的键,比如 _User__value
- 你写 obj.__value,解释器就真的去字典里找 "__value" 这个 key —— 找不到,直接抛 AttributeError
- 这不是权限拦截,是名字对不上,就像查人名簿却写了错别字
点号访问不走自定义逻辑
点号(.)是 Python 最基础的属性访问语法,它绕过 __getattribute__ 的常规拦截(除非你手动重写并主动处理),直接查实例字典和类字典。
- 它不会自动把 __value 映射成 _User__value
- 也不会触发 property、描述器或 __getattr__ —— 那些机制得名字先“存在”或“查无此名”后才介入
- 所以点号看到的,就是字面上的名字;名字被改了,它就束手无策
为什么类方法里却能用点号访问?
因为在类定义内部,所有对 self.__value 的引用,都会被 Python 编译器提前替换成 self._User__value。
- 你写的代码是 self.__value,但实际编译后执行的是 self._User__value
- 所以方法体内的点号访问,对象字典里真有这个 key,自然成功
- 这说明“能访问”不是因为权限放宽,而是名字在源头就被统一替换了
想动态访问?得用对的名字
如果非要在外部读取,必须用改写后的完整名称:
- getattr(obj, '_User__value') —— 安全、推荐
- obj._User__value —— 可行,但破坏封装,不建议用于生产
- obj.__dict__.get('_User__value') —— 直接查字典,也有效
靠点号硬写原始私有名,注定失败——不是语言卡你,是你没给对钥匙。

















