Python 对象名前的单下划线和双下划线有什么区别?

单下划线 _name 是"内部使用"的命名约定(不强制),双下划线 __name 触发名称改写(name mangling)避免子类属性冲突。本文详解两者区别与适用场景。

最佳实践
Python 对象名前的单下划线和双下划线有什么区别?封面

一句话区别:_name(单下划线)只是约定俗成的"私有"标记,靠自觉,外部照样能访问;__name(双下划线)会触发解释器的名称改写机制,属性名被改成 _类名__name,主要用来避免父子类之间的意外同名冲突,两者都不是真正的私有。

单下划线:约定大于强制

class Service:
    def __init__(self):
        self._cache = {}  # 提示:内部实现,请勿直接动

s = Service()
print(s._cache)  # 可以访问,只是不该这么做

单下划线向读代码的人(和 IDE)传达"这是内部细节"的信号。from module import * 时,单下划线开头的名字默认不会被导入。

双下划线:名称改写

class MyClass:
    def __init__(self):
        self.__private = 42

obj = MyClass()
obj.__private            # AttributeError
obj._MyClass__private    # 42,改写后的真实名字

以两个下划线开头(且不以两个下划线结尾)的名字会被解释器改写成 _类名__原名。这样父类的 __state 和子类的 __state 实际是两个不同属性,不会互相覆盖。

其他下划线形式速查

写法 含义
_name 约定私有 / 临时占位
__name 名称改写,防子类冲突
__name__ Python 内置魔法名(如 __init__),不要自己造
_ 单独使用 交互解释器中表示上一个结果;代码里表示"不关心这个变量"(如 for _ in range(3)

观测云对照

用命名约定划分 SDK 封装边界。 在内部封装的日志上报 SDK 里,把不希望业务方触碰的缓冲队列、发送线程命名为 _buffer_sender,配合文档说明;观测云 APM 探针本身的内部字段也遵循同样约定,业务方只面向公开 API 编程。

常见问题(FAQ)

Q:双下划线能实现真正的私有吗?
A:不能。_MyClass__private 依然能访问到,它只是防"意外",不防"故意"。

Q:自己定义 __foo__ 这样的名字可以吗?
A:不建议。这种形式保留给语言本身,未来版本新增魔法方法可能与之冲突。

Q:父类想保护属性不被子类覆盖,用哪个?
A:用双下划线 __attr,名称改写后子类的同名属性不会覆盖父类的。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台