Python:如何阻止类实例的属性被外部修改?
如何阻止直接修改Python类实例的属性?
这个问题的核心在于Python默认的类属性是公开可直接修改的,要阻止外部直接赋值修改data属性,我们可以通过私有属性+只读属性装饰器的方式来实现,同时还能避免外部通过引用修改内部数据的问题。
解决方案一:使用私有属性与@property只读访问
Python中,以双下划线__开头的属性会触发名称修饰(name mangling),变成_类名__属性名的形式,虽然不是绝对的“私有”,但能有效阻止常规的外部直接访问和赋值。配合@property装饰器,我们可以提供只读的访问接口,同时返回数据的副本,彻底避免外部修改内部状态。
修改后的完整代码如下:
class Matrix: def __init__(self, data): # 用私有属性存储原始数据,避免外部直接访问 self.__data = data def __str__(self): display = [] for row in self.__data: display.append(str(row)) return '\n'.join(display) @property def data(self): # 返回每行的副本,确保外部拿到的不是内部数据的引用 return [row.copy() for row in self.__data]
测试效果
运行以下代码验证:
a = Matrix([[1, 2], [3, 4]]) print(a.data) # 输出: [[1, 2], [3, 4]] # 尝试直接赋值会触发AttributeError # a.data = [[0,0],[0,0]] # 这行代码会报错:AttributeError: can't set attribute # 即使修改返回的副本,也不会影响内部的原始数据 temp = a.data temp[0][0] = 99 print(a.data) # 输出依然是: [[1, 2], [3, 4]]
为什么这样有效?
- 私有属性
__data:Python会自动把__data重命名为_Matrix__data,外部代码无法直接通过a.__data访问,常规赋值操作a.data = ...会因为没有对应的setter而报错。 - 返回数据副本:如果只是返回
self.__data,外部虽然不能重新赋值,但可以通过列表的可变特性修改元素(比如a.data[0][0] = 0)。返回row.copy()的列表副本,能彻底切断外部与内部数据的引用关联。
备选方案:使用冻结数据类(适合简单场景)
如果你的类不需要复杂的内部逻辑,也可以用dataclasses的冻结特性来创建不可变对象:
from dataclasses import dataclass, field from typing import List @dataclass(frozen=True) class Matrix: data: List[List[int]] = field(default_factory=list) def __str__(self): display = [] for row in self.data: display.append(str(row)) return '\n'.join(display)
此时尝试a.data = [[0,0],[0,0]]会触发FrozenInstanceError,不过要注意:冻结数据类只是阻止属性重新赋值,内部的列表依然是可变的,如果要完全不可变,需要把内部元素也改成不可变类型(比如tuple)。
内容的提问来源于stack exchange,提问作者BrainBug
相关产品推荐
相关产品推荐

