直接删掉 setter 方法就能实现只读,因为 @property 仅定义 getter;未声明 @xxx.setter 时,Python 在赋值时抛出 AttributeError,属语言级强制约束,而非约定。

为什么直接删掉 setter 方法就能实现只读?
因为 @property 本身只定义 getter;一旦你没写对应的 @xxx.setter,Python 就会拒绝赋值操作,抛出 AttributeError: can't set attribute。这不是靠“隐藏”或“约定”,而是语言层面的强制约束。
常见错误是写了空的 setter:
@name.setter
def name(self, value):
pass # ❌ 这会让属性变成可写,且不报错但也不生效
真正只读的做法就是——干脆不定义 setter。
如何让只读属性支持初始化后不可变,但又允许构造时赋值?
只读 ≠ 初始化时不能设。关键是把值存进实例字典(比如 self._name),然后用 @property 暴露只读接口。构造函数里照常赋值即可。
示例:
class Person:
def __init__(self, name):
self._name = name # ✅ 允许在 __init__ 中设
<pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">@property
def name(self):
return self._name # ✅ 只提供读,不提供写
使用时:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
Person("Alice").name → 正常返回"Alice"-
p = Person("Alice"); p.name = "Bob"→ 立即报错:AttributeError: can't set attribute
哪些场景下“只读”会意外失效?
只读是针对属性访问语法(obj.attr)的保护,不是内存级防护。以下操作仍能绕过:
- 直接修改底层存储:如
p._name = "Hacker"(只要没加双下划线 name mangling) - 通过
setattr(p, "_name", ...)或p.__dict__["_name"] = ... - 子类重定义同名 property 并加上 setter
所以只读属性本质是“协议式约束”:告诉调用方“你不该改”,而不是“你改不了”。真要防误改,得配合命名规范(如单下划线前缀)、文档说明,或在 __setattr__ 里做运行时检查(但代价高,一般不推荐)。
用 @property 定义只读属性会影响性能或继承吗?
影响很小,但存在:
- 每次访问都触发函数调用,比直接读实例变量略慢(微秒级,通常可忽略)
- 继承时,子类可以覆盖父类的
@property,但如果只重写 getter 不提 setter,子类属性仍是只读;若子类显式加了@xxx.setter,就变成可写 —— 这是预期行为,不是 bug - 注意:如果父类 property 基于某个私有字段(如
_value),子类直接改_value会导致 getter 返回值“突变”,这种耦合容易被忽略
最易被忽视的一点:只读属性无法被 dataclasses.field(init=False) 或 attrs.field(init=False) 直接替代,因为它们控制的是初始化参数,不等价于运行时访问控制。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










