跳转到主内容
极星编程网:以代码为星,赴技术山海!

Python 如何实现“只读属性”但允许在 init 里赋值

Python实现只读属性的核心思路是用私有属性存储值、property提供只读访问,并在__init__中直接赋值私有变量;推荐property+私有属性,可选__slots__增强防护或描述符复用。 Python 中实现“只读属性”但允许在
__init__
中赋值,核心思路是:**用私有属性存储值,通过 property 提供只读访问,并在初始化阶段绕过 property 直接写私有变量**。这样既保证实例创建后无法修改,又保留构造时的灵活性。 用 property + 私有属性(推荐) 这是最清晰、最 Pythonic 的方式。关键在于: property 的 setter 不定义或抛出异常,而
__init__
直接给底层私有属性(如
self._x
)赋值 。 示例:
class Person: def __init__(self, name): self._name = name # ✅ 允许在 init 中直接赋值
@property
def name(self):
    return self._name

# ❌ 不定义 setter,或显式禁止
@name.setter
def name(self, value):
    raise AttributeError("name is read-only")
Python 3.14.3微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。下载 立即学习 “ Python免费学习笔记(深入) ”; 使用效果:
p = Person("Alice")
→ 成功
p.name
→ 返回
"Alice"
p.name = "Bob"
→ 抛出
AttributeError
用 __slots__ + property(增强防护) 如果想进一步防止用户通过动态设置
p._name = ...
绕过限制,可结合
__slots__
封锁实例字典:
class Person: __slots__ = ("_name",) # 只允许 _name 属性
def __init__(self, name):
    self._name = name

@property
def name(self):
    return self._name
立即学习 “ Python免费学习笔记(深入) ”; 此时:
p._name = "new"
仍可行(因为
__slots__
不限制私有属性写入),但
p.age = 10
会报错,且无法新增任意属性干扰逻辑。 用描述符(适合复用场景) 若多个类都需要类似只读字段,可封装成描述符:
class ReadOnly: def __init__(self, default=None): self.default = default self.name = None # 后续由 __set_name__ 填充
def __set_name__(self, owner, name):
    self.name = f"_{name}"

def __get__(self, obj, objtype=None):
    if obj is None:
        return self
    return getattr(obj, self.name, self.default)

def __set__(self, obj, value):
    if not hasattr(obj, self.name):  # 仅允许第一次设置(即 init 阶段)
        setattr(obj, self.name, value)
    else:
        raise AttributeError(f"{self.name[1:]} is read-only")
class Person: name = ReadOnly()
def __init__(self, name): self.name = name # ✅ 第一次赋值成功
立即学习 “ Python免费学习笔记(深入) ”; 注意:该描述符依赖“首次赋值”判断,适用于简单场景;复杂逻辑建议回归 property 方案。 不推荐的做法:重写 __setattr__ 虽然可以拦截所有属性赋值,但容易误伤(比如影响
self._name
在
__init__
中的设置),需额外维护白名单,代码易出错、难维护,一般不建议。

相关文章