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

如何在Python中将可变属性设为只读?避免通过property修改可变对象

如何让@property返回的列表不可修改

先看初始实现:

class Foo:
    def __init__(self, data: list):
        self._data = data
    
    @property
    def data(self):
        return self._data

这种写法能阻止obj.data = [1, 2, 3]这类直接赋值操作,但因为列表是可变对象,外部仍能通过obj.data.append(10)修改内部数据。需求是允许类内部通过self._data修改数据,但对外暴露的obj.data要保持不可变。

你尝试的返回切片副本方案是可行的:

class Foo:
    def __init__(self, data: list):
        self._data = data
    
    @property
    def data(self):
        copy = self._data[:]
        return copy

针对这个需求,还有以下几种替代方案:

1. 返回元组(tuple)

把内部列表转成元组返回,元组是Python原生的不可变序列类型,外部无法直接修改其内容:

class Foo:
    def __init__(self, data: list):
        self._data = data
    
    @property
    def data(self):
        return tuple(self._data)
  • 优势:无需额外拷贝逻辑,性能高效;天然不可变,完全符合对外只读的需求。
  • 劣势:如果外部需要列表类型的操作,得自行转换,但这也正好限制了对数据的修改。

2. 深拷贝(针对嵌套可变结构)

如果你的列表包含嵌套的可变对象(比如列表里套列表),浅拷贝(切片)无法阻止外部修改内部嵌套元素,这时可以用深拷贝彻底切断关联:

import copy

class Foo:
    def __init__(self, data: list):
        self._data = data
    
    @property
    def data(self):
        return copy.deepcopy(self._data)
  • 优势:完全隔离内外数据,即使嵌套可变对象也无法修改内部原数据。
  • 劣势:深拷贝性能开销较大,适合数据量较小的场景。

3. 自定义不可变列表包装类

如果想保留列表的访问方式(索引、切片、长度获取等),但屏蔽所有修改方法,可以自定义一个继承自Sequence的不可变包装类:

from collections.abc import Sequence

class ImmutableList(Sequence):
    def __init__(self, data):
        self._data = data
    
    def __getitem__(self, index):
        return self._data[index]
    
    def __len__(self):
        return len(self._data)

class Foo:
    def __init__(self, data: list):
        self._data = data
    
    @property
    def data(self):
        return ImmutableList(self._data)
  • 优势:外部可以像使用普通列表一样访问数据,但没有append、pop等修改方法,既符合使用习惯又保证只读。
  • 劣势:需要额外定义包装类,代码量稍多。

方案对比

你最初的切片浅拷贝方案,对于一维简单类型的列表来说是非常高效且合理的选择,完全满足需求。如果是嵌套结构或需要更严格的只读约束,可以根据场景选择上面的其他方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:57:34