在 Python 中,双下划线名称改写(Name Mangling) 是一种用于类中“伪私有”属性的机制,目的是避免子类意外覆盖父类的同名属性。其规则是:
- 当一个标识符(如属性名或方法名)以 两个前导下划线
__开头,且不以两个或更多下划线结尾(即不是__name__这类特殊方法),Python 解释器会自动将其重命名为_类名__name的形式。 - 该改写发生在定义时(编译期),仅适用于类定义内部的名称(即在 class body 中直接出现的
__xxx)。 - 目的是“命名混淆”,而非真正意义上的访问控制(Python 没有真正的私有成员)。
✅ 示例:
class MyClass:
def __init__(self):
self.__value = 42 # → 被改写为 _MyClass__value
self.public = "ok"
def get_value(self):
return self.__value # 实际访问的是 self._MyClass__value
obj = MyClass()
print(obj.get_value()) # 42
print(obj._MyClass__value) # ✅ 可访问(但不推荐)
# print(obj.__value) # ❌ AttributeError: 'MyClass' object has no attribute '__value'
⚠️ 注意:
__value__(前后双下划线)→ 不触发 name mangling(是特殊方法/属性,如__init__、__str__)。- 单下划线
_value→ 约定为“受保护”,不触发改写,仅语义提示。 - 若类名以双下划线开头(如
__Base),则__value在其中仍会被改写为_Base__value;但若类名本身是__开头且无后缀(极少见),改写行为可能受限(不推荐)。
Python 不提供“真正的私有成员”(即编译器/解释器强制禁止外部访问的机制),根本原因在于其核心设计哲学:“我们都是 consenting adults”(我们都是有责任心的成年人)。
这意味着 Python 选择信任开发者,强调约定优于强制、透明性与灵活性优先于封闭性,而非通过语言机制施加访问限制。
具体原因包括:
✅ 哲学驱动:
Python 倡导简洁、可读、可调试、可扩展。强制私有会增加语言复杂性(如访问控制检查、反射限制),违背“简单胜于复杂”的 Zen of Python 原则。
✅ 动态性与内省需求:
Python 是高度动态的语言(支持 getattr、setattr、dir()、__dict__、猴子补丁等)。若强行禁止访问,将破坏调试、序列化(如 pickle)、ORM 映射、测试(如 patch 私有方法)、框架开发(如 Django/Flask 内部钩子)等关键场景。
✅ 双下划线改写(Name Mangling)已足够满足实际需求:
- 它不是为了“阻止访问”,而是防止意外覆盖(尤其是继承时的命名冲突);
- 它是可预测、可绕过、可调试的(如
obj._Class__attr),既提供了封装提示,又不牺牲灵活性; - 真正需要强约束的场景(如安全敏感模块),应通过文档、类型提示(
typing.Private)、静态检查工具(mypy)、或运行时封装(property + 验证逻辑)来实现,而非语言级封锁。
✅ 历史与一致性:
Python 的设计深受 Modula-3 和 ABC 语言影响,强调显式、直接和一致。Java/C++ 的 private 带来大量样板(getter/setter)、反射绕过漏洞、以及继承模型复杂化,Python 主动规避了这些权衡。
💡 类比:Python 的
__name就像给变量贴了个醒目的标签:“这是内部用的,请勿随意触碰”——但如果你真有合理理由(比如单元测试或调试),撕掉标签也完全可行,且不会损坏系统。


550

被折叠的 条评论
为什么被折叠?



