python - 在 Python 2.7 中包装大列表以使其不可变

标签 python list wrapper immutability

如果我有一个非常大的 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/

相关文章:

c# - 读取和修改通用 List<T> 中的对象

c++ - 使用 typedef 包装函数

Python 不允许在解包时注释变量的类型

python - Pandas:使用 groupby 重建数据透视表

python - 替换 Python 列表中的重复字符串

python - 如何创建一个列表或一组 N 深对象中的每个排列

c++ - 为 C++ 库创建自动 C 包装器?

maven - 如何要求 IntelliJ 使用包装的 maven(mvnw 或 mvnw.cmd)?

python - 为什么我的 venv 使用的 pip 版本与我安装的不同

Python:通过循环最小化函数