如果我有一个非常大的 list
(>100k 元素)可以通过函数调用从某个对象中检索,有没有办法包装该列表以使其对调用者不可变将其复制到 tuple
?
在下面的示例中,我只有一个 list
字段,但该解决方案应该适用于任意数量的 list
字段。
class NumieHolder(object):
def __init__(self):
self._numies = []
def add(self, new_numie):
self._numies.append(new_numie)
@property
def numies(self):
# return numies embedded in immutable wrapper/view
return ??? numies ???
if __name__ == '__main__':
nh = NumieHolder()
for numie in xrange(100001): # >100k holds
nh.add(numie)
# messing with numies should result in exception
nh.numies[3] = 4
# but I still want to use index operator
print '100th numie:', nh.numies[99]
我会知道如何编写以这种方式运行的适配器,但如果已经有一些我不知道的标准解决方案(即在标准库或广为人知的库中),我很感兴趣。
最佳答案
不幸的是,标准库(或其他著名的库)中没有这样的包装器。主要原因是 list
应该是具有索引访问权限的可变序列类型。 不可变 序列类型将是一个元组
,正如您自己所说的那样。所以通常,使列表不可变的标准方法是通过调用 tuple(lst)
将其变成元组。
这显然不是您想要的,因为您希望避免复制所有元素。因此,您可以创建一个包装列表的自定义类型,并提供所有非修改方法 list
还支持:
class ImmutableList:
def __init__ (self, actualList):
self.__lst = actualList
def __len__ (self):
return self.__lst.__len__()
def __getitem__ (self, key):
return self.__lst.__getitem__(key)
def __iter__ (self):
return self.__lst.__iter__()
def __reversed__ (self):
return self.__lst.__reversed__()
def __contains__ (self, item):
return self.__lst.__contains__(item)
def __repr__ (self):
return self.__lst.__repr__()
def __str__ (self):
return self.__lst.__str__()
>>> original = [1, 2, 3, 4]
>>> immutable = ImmutableList(original)
>>> immutable
[1, 2, 3, 4]
>>> immutable[2]
3
>>> for i in immutable:
print(i, end='; ')
1; 2; 3; 4;
>>> list(reversed(immutable))
[4, 3, 2, 1]
>>> immutable[1] = 4
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
immutable[1] = 4
TypeError: 'ImmutableList' object does not support item assignment
另一种方法是子类型 list
并覆盖 __setitem__
和 __delitem__
来引发异常,但我建议不要这样做,因为list
的子类型应该具有与 list
本身相同的接口(interface)。另一方面,上面的 ImmutableList
只是一些可索引的序列类型,它恰好包装了一个真正的列表本身。除此之外,将它作为 list
的子类型实际上需要你复制一次内容,所以如果你不想重新创建所有这些项目(这似乎是你的点——否则你可以只使用 tuple
)。
关于python - 在 Python 2.7 中包装大列表以使其不可变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21000994/