Python中“只读私有属性”通过双下划线名称改写加@property实现:底层用self.__name存储,@property定义同名只读getter,无setter时赋值报AttributeError,既防误操作又符合Python风格。

在 Python 中,“只读的私有属性”不是单一语法能一步到位的概念,而是通过组合手段实现的约定性保护:用双下划线 __ 实现名称改写(name mangling)来私有化存储,再用 @property 暴露只读访问接口。它既不让外部直接读写底层变量,也不允许赋值修改——这是最常用、最清晰、也最符合 Python 风格的做法。
用 __ 开头 + @property 实现真正实用的只读私有属性
核心逻辑是:把真实数据存为私有实例变量(如 self.__name),然后用 @property 定义同名只读属性方法。Python 会自动把 obj.name 转为调用该 getter,而因为没写 @name.setter,任何赋值都会触发 AttributeError。
- 构造时可初始化:
self.__name = name在__init__中合法赋值 - 外部只能读:
inst.name返回值,正常工作 - 外部不能写:
inst.name = "new"立即报错AttributeError: can't set attribute - 外部无法直接访问私有变量:
inst.__name报错;inst._ClassName__name虽技术上可行,但属明确违反约定
为什么不用 __setattr__ 或空 setter?
有些资料提到重写 __setattr__ 或定义空的 @xxx.setter,但这两种都不推荐:
-
__setattr__是全局拦截,容易误伤其他属性,且性能开销明显,属于“过度防御” - 空的 setter(
@name.setter下只写pass)会让赋值语句静默成功,看似可写实则无效——这反而破坏了只读语义,极易引发隐蔽 bug
只读 ≠ 绝对不可变,关键看使用场景
Python 的只读属性本质是“协议级防护”,不是内存级锁:
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 它有效防止常规误操作和 IDE 自动补全诱导的赋值
- 不阻止开发者主动绕过(如直接操作
inst._Person__age或setattr(inst, "_Person__age", ...)) - 若需更强保障(如防子类篡改),应配合文档说明、命名规范(如单下划线
_name表示“受保护”)、或在关键业务中做运行时校验
一个完整可运行的例子
下面代码定义了一个带只读私有属性 id 的 User 类:
class User:
def __init__(self, user_id):
self.__id = user_id # 私有存储,仅在内部初始化
<pre class="brush:php;toolbar:false;">@property
def id(self):
return self.__id # 只读暴露使用
u = User("U-12345") print(u.id) # → "U-12345"










