Python私有字段通过名称重整(如__name→_ParentClass__name)被继承并初始化,子类无法直接访问因重整名不匹配;应通过@property封装访问,避免硬编码重整名。

私有字段(以双下划线 __ 开头)在 Python 继承链中**不是消失或被跳过,而是被“重命名”后依然存在并完成初始化**。子类方法无法用原始名称访问父类私有字段,根本原因不是权限封锁,而是名称重整(name mangling)导致存储名与访问名不匹配。
私有字段确实被继承并初始化了
父类的 __init__ 被调用时(通常通过 super().__init__()),其私有字段如 self.__name 会被转换为 self._ParentClass__name 并写入实例字典。调用 vars(子类实例) 或查看 实例.__dict__ 可清晰看到该字段已存在,例如:{'_Person__name': '张三'}。它参与了对象构建,只是名字变了。
子类无法直接访问,因为名称重整作用域不同
在子类方法中写 self.__name,Python 会按子类类名重整为 _ChildClass__name,而该键在实例字典中并不存在——父类存的是 _ParentClass__name。两者指向不同内存位置,自然读不到。
- 父类中
self.__name→ 实际存为_Person__name - 子类中
self.__name→ 实际查的是_Student__name - 二者无关联,也不共享值
安全访问的唯一推荐方式:靠封装,不靠硬编码
父类应提供公开的属性接口(@property 和 @xxx.setter),把对私有字段的读写逻辑封装在内部。子类只操作这个公开名,完全不必知道底层是否用了 __name。
- 父类定义
@name.getter和@name.setter,内部操作self.__name - 子类直接使用
self.name = ...或print(self.name) - 若需扩展校验(如学生姓名必须含学号),可在子类重写 setter,并调用
super().name.fset(self, value)
绝对要避免的操作
手动拼接重整后的名称(如 self._Person__name)看似能读取,实则破坏封装、耦合实现细节:
- 父类改名后,所有硬编码的
_OldName__field全部失效 - 调试时临时用
getattr(obj, '_Person__name', None)可接受,但生产代码禁用 - 这不是“绕过限制”,而是主动放弃设计契约

















