You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python为何允许同名实例属性?双下划线属性访问与赋值异常问题解析

为什么Python中双下划线属性会出现这种奇怪的访问现象?

这是个非常有意思的问题,核心原因在于Python的**名称修饰(Name Mangling)**机制,咱们来一步步拆解清楚:

1. 第一次访问报错的原因

当你在类内部定义以双下划线开头的属性(比如__secret)时,Python会自动对这个属性名做「名称修饰」——它会把属性名修改为_类名__属性名的格式,目的是避免子类意外覆盖父类的私有属性,或者外部代码不小心修改到类内部的属性。

看你第一个例子的代码:

class genericClass:
    def __init__(self):
        self.__secret = "secret"
generic_object = genericClass()
print(generic_object.__secret)  # 报错:AttributeError

这里真正存储的属性其实是_genericClass__secret,而不是你写的__secret,所以直接访问generic_object.__secret自然会提示属性不存在。

2. 第二次赋值后能访问的原因

当你执行generic_object.__secret = "not a secret anymore"时,你并不是在修改原来的那个__secret(也就是被修饰后的_genericClass__secret),而是给这个实例新增了一个完全独立的、名为__secret的公共属性。

这个新属性和类内部定义的那个没有任何关联——因为名称修饰只在类定义的内部生效,在类外部直接给实例赋值双下划线开头的属性时,Python不会做任何修饰,只会把它当作普通的属性名存储。

3. 实例确实存在两个不同的__secret相关属性

是的,这时候你的实例generic_object同时拥有两个属性:

  • 类内部定义的、被修饰后的私有属性:_genericClass__secret,值为"secret"
  • 你后来新增的公共属性:__secret,值为"not a secret anymore"

你可以用dir()函数验证这一点:

class genericClass:
    def __init__(self):
        self.__secret = "secret"
generic_object = genericClass()
generic_object.__secret = "not a secret anymore"
print(dir(generic_object))

输出结果里会同时出现_genericClass__secret和__secret。也可以分别访问这两个属性来确认:

print(generic_object._genericClass__secret)  # 输出: secret
print(generic_object.__secret)               # 输出: not a secret anymore

总结

Python的双下划线属性不是严格意义上的「私有属性」(你依然可以通过_类名__属性名的方式访问),它本质是一种名称修饰机制,用来减少属性名冲突的概率。而在类外部直接给实例赋值双下划线开头的属性时,不会触发这个修饰机制,只会创建一个新的普通属性,这就是你看到两种不同现象的根本原因。

内容的提问来源于stack exchange,提问作者Emi Buliga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:08:14