为何Python中仅含Getter的列表属性可修改元素?
为什么仅定义Getter的属性仍能修改列表元素?
这是因为你混淆了修改属性的绑定关系和修改可变对象的内部状态,两者完全是两回事:
@property的限制只针对“属性绑定”
当你尝试直接给li.l赋值(比如li.l = [1,2,3]),这属于修改属性的绑定,此时因为没有定义setter,Python才会抛出AttributeError: can't set attribute,这符合你最初的预期。你实际做的是修改可变对象的内部状态
li.l[0] = "this shouldn't work"的执行逻辑是:- 先通过getter获取
__a_private_attribute指向的列表对象(返回的是该列表的引用,不是副本) - 调用列表的
__setitem__方法修改索引0的元素
这个过程没有改变li.l指向的对象,只是改变了对象本身的内容——而@property的getter不会限制你对返回对象的操作,尤其是像列表这种可变对象。
- 先通过getter获取
如何阻止这种修改?
如果要彻底防止外部修改内部列表的内容,你需要在getter中返回列表的副本,而不是原对象的引用:
class AList: def __init__(self, l): self.__a_private_attribute = l.copy() # 初始化时也存副本,避免外部传入的列表直接影响内部 @property def l(self): return self.__a_private_attribute.copy() # 返回副本,外部修改不会影响原属性 if __name__ == '__main__': li = AList([0]) li.l[0] = "this shouldn't work" print(li.l) # 输出 [0],修改的只是副本,原属性不受影响
另外补充:Python的私有属性(双下划线开头)只是做了名字修饰(变成_AList__a_private_attribute),本质上还是能通过特殊方式访问,但这个问题的核心和私有性无关,完全是可变对象的特性导致的。
内容的提问来源于stack exchange,提问作者Jakub Watson-Jones
相关产品推荐
相关产品推荐

