__name 是名称改写而非访问控制:赋值 p.__name = "x" 创建新公有属性,不影响原 _Person__name;p._Person__name 可直接访问因改名是单向机械替换;动态生成的 "__name" 不触发改名。

Python 的 __name 不是访问控制机制,而是名称改写(name mangling)规则——它不阻止访问,只改变名字。你“能访问到”,是因为解释器根本没拦你;你“以为改了却没生效”,是因为赋值时创建的是新属性,不是原私有变量。
为什么 p.__name = "x" 不影响 get_name() 返回值?
这是最常被误解的一点:这行代码根本没动类里定义的私有属性,只是给实例 p 动态加了一个叫 __name 的公有属性。
-
p.__name = "x"→ 新增实例属性p.__name(类型为公有,和类定义无关) -
p._Person__name→ 才是__init__中self.__name实际存储的位置 -
get_name()内部读的是self._Person__name,自然不受上面那行影响
为什么 p._Person__name 能直接读到值?
因为 name mangling 是单向重命名,不是加密或权限拦截。解释器只在类定义体中扫描 __xxx 形式的名字,并自动替换成 _ClassName__xxx;外部用这个修饰名访问,完全合法。
- 这个行为在所有 Python 3.x 版本中稳定,但属于实现细节,不建议依赖
- IDE 和静态检查工具(如 mypy)通常会警告这种写法
- 如果你在调试时临时用它查值,没问题;写进业务逻辑里,等于主动放弃封装契约
_name 和 __name 的根本区别在哪?
前者是人看的约定,后者是解释器做的机械改名。它们解决的问题完全不同。
立即学习“Python免费学习笔记(深入)”;
-
_name:无任何语法或运行时干预,纯靠团队协作和文档约束 -
__name:触发 name mangling,主要目的是避免子类中同名属性意外覆盖父类内部字段 - 比如子类也定义了
self.__id,它会被改写成_Child__id,不会和父类的_Parent__id冲突
动态生成的 "__name" 字符串不会被 mangling
name mangling 只作用于类定义时**字面量出现**的双下划线名。运行时拼出来的,解释器压根不识别。
例如:setattr(self, "__name", "x") 不会触发改名,self.__name 就是真的叫 __name,和 _Person__name 完全无关。
这点极容易被忽略——你以为用了双下划线就安全,结果动态设置时绕过了所有保护。


















