摘要:其中,双前导下划线(__name)但不以双下划线结尾的名字会触发一种机制,称为“名称改写”(Name Mangling)。
在 Python 中,类的属性和方法名可以使用下划线来表达不同的含义。
其中,双前导下划线(__name)但不以双下划线结尾的名字会触发一种机制,称为“名称改写”(Name Mangling)。
名称改写的主要作用是:在类定义阶段,Python 会自动将这类名字改写为 _类名__name 的形式,从而避免在继承关系中被子类意外覆盖。
一、名称改写的规则
1、触发条件
仅当名字以两个下划线开头(__name),但不以两个下划线结尾时才会触发。
比如:
__attr → 会被改写。
__attr__ → 不会被改写(保留给特殊方法)。
_attr → 不会被改写,只是“内部使用”的约定。
2、改写时机
名称改写发生在类定义阶段,即类体执行时。
Python 会根据类名生成改写后的名字,因此相同的 __name 在不同的类中会得到不同的改写结果。
3、改写规则
在类定义时,将 __name 改写为 _类名__name。
4、完整示例
class Demo:def __init__(self):self.__hidden = 123 # 双前导下划线属性def __private_method(self): # 双前导下划线方法return "这是私有方法"def access(self):# 在类内部,依旧用定义时的名字即可return self.__hidden, self.__private_methodd = Demo# 1. 实例字典中的实际存储print(d.__dict__)# {'_Demo__hidden': 123}# 2. 类字典中的方法名称print([name for name in Demo.__dict__ if "private" in name])# ['_Demo__private_method']# 3. 外部直接访问会报错# print(d.__hidden) # AttributeError# print(d.__private_method) # AttributeError# 4. 可以通过改写后的名字访问print(d._Demo__hidden) # 123print(d._Demo__private_method) # 这是私有方法# 5. 在类内部调用仍然正常print(d.access) # (123, '这是私有方法')(1)定义时写的是 __hidden,但存储在实例字典里时变成了 _Demo__hidden。
(2)定义时写的是 __private_method,在类字典里变成了 _Demo__private_method。
(3)类内部写 self.__hidden 时,Python 会自动替换成 _Demo__hidden,所以访问正常。
(4)类外访问时,必须显式写改写后的名字才能成功。
二、避免子类覆盖
如果没有名称改写,子类可能会无意中覆盖父类的属性或方法。
class Base:def __init__(self):self.value = 100 # 普通属性class Child(Base):def __init__(self):super.__init__self.value = 200 # 覆盖了父类的同名属性c = Childprint(c.value) # 200(父类的值被覆盖)使用双前导下划线,就能避免这种冲突:
class Base:def __init__(self):self.__value = 100 # 实际改写为 _Base__valuedef get_value(self):return self.__valueclass Child(Base):def __init__(self):super.__init__self.__value = 200 # 实际改写为 _Child__valuec = Childprint(c.get_value) # 100(父类方法仍然访问 _Base__value)print(c.__dict__) # {'_Base__value': 100, '_Child__value': 200}父类和子类各自拥有独立的属性,不会互相覆盖。
三、方法中的名称改写
class A:def __private_method(self):print("A.__private_method called")def call(self):self.__private_methodclass B(A):def __private_method(self):print("B.__private_method called")b = Bb.call# 输出: A.__private_method called(1)A.__private_method 改写为 _A__private_method。
(2)B.__private_method 改写为 _B__private_method。
(3)子类不会覆盖父类方法。
四、注意事项与误区
1、名称改写不是严格的“私有”机制
Python 没有真正的私有属性,名称改写的目的在于避免冲突,而不是提供安全保护。
外部仍可以通过 _类名__name 形式访问。
2、不要滥用双前导下划线
如果只是“内部使用”,推荐用单下划线 _name。
双前导下划线仅在需要避免继承冲突时使用。
3、不要与特殊方法混淆
__init__、__len__、__str__ 等属于 Python 的魔术方法,不会触发名称改写。
小结
名称改写:当名字以双前导下划线开头但不以双下划线结尾时,Python 会将其改写为 _类名__name 。
作用:避免子类覆盖父类同名属性或方法。
注意:这不是严格的私有机制,依旧可以通过改写后的名字访问。
使用场景:在继承层次中保护基类实现不被子类误覆盖。
“点赞有美意,赞赏是鼓励”
来源:恬恬课堂