Python中的不可变列表
我想在整个应用中使用一个不可变的列表。我以为把这个列表放在一个元组里就可以实现这个目的,但实际上,tuple(list)
并不是把列表包裹起来,而是复制了列表里的元素。
>>> a = [1, 2, 3, 4]
>>> b = tuple(a)
>>> b
(1, 2, 3, 4)
>>> a[0] = 2
>>> b # was hoping b[0] to be 2
(1, 2, 3, 4)
有没有简单的方法可以创建一个基于这个列表的“视图”,这个视图是不可变的(也就是说对这个视图的操作不会改变它),但又能反映出原列表的任何变化呢?
我知道这个问题之前有人问过,但没有一个回答真正解决这个视图和原列表之间的关系(实际上,有些评论甚至建议元组的工作方式和我希望的一样,但上面的代码片段却表明并非如此)。
1 个回答
12
如果你不想复制数据,而是想传递一个不可更改的“列表”,一种方法是创建一个代理对象,这个代理对象是列表的一个副本,它禁用所有可以改变内容的方法,同时把读取的方法指向原始列表。大概就是这样:
from collections import UserList
class ReadOnlyList(UserList):
def __init__(self, original):
self.data = original
def insert(self, index=None, value=None):
raise TypeError()
__setitem__ = insert
__delitem__ = insert
append = insert
extend = insert
pop = insert
reverse = insert
sort = insert
通过继承“UserList”,可以确保所有处理列表数据的代码都会通过公开的Python方法来执行,更棒的是,其他的方法已经实现,并且会指向内部的data
属性。
下面是2014年原始的回答,主要针对Python 2
class ReadOnlyList(list):
def __init__(self, other):
self._list = other
def __getitem__(self, index):
return self._list[index]
def __iter__(self):
return iter(self._list)
def __slice__(self, *args, **kw):
return self._list.__slice__(*args, **kw)
def __repr__(self):
return repr(self._list)
def __len__(self):
return len(self._list)
def NotImplemented(self, *args, **kw):
raise ValueError("Read Only list proxy")
append = pop = __setitem__ = __setslice__ = __delitem__ = NotImplemented
And, of course, implement whatever other methods you judge necessary, either raising the error (or ignoring the writting instruction) - or acessing the corresponding object in the internal list.