用Python2.7包装大列表使其成为immutab

2024-06-25 23:26:21 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我知道如何编写这样的适配器,但我感兴趣的是是否已经有一些我不知道的标准解决方案(即在标准库或广为人知的库中)。在


Tags: ingtselfadd元素new标准return
2条回答

不幸的是,标准库(或其他著名的库)中没有这样的包装器。主要原因是list应该是一个具有索引访问的可变序列类型。不可变的序列类型应该是tuple,正如您自己所说的那样。所以通常,使列表不可变的标准方法是通过调用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__()
^{pr2}$

另一种方法是使用子类型list并重写__setitem__和{}来引发异常,但我建议不要这样做,因为{}的子类型与{}本身具有相同的接口。^另一方面,上面的{}只是一些可索引的序列类型,它恰好包装了一个真正的列表本身。除此之外,将其作为list的子类型实际上需要您复制一次内容,因此如果您不想重新创建所有这些项,包装肯定会更好(这似乎是您的重点,否则您可以使用tuple)。在

请参阅Emulating Container Types,了解您想要实现或重写的“特殊”方法。也就是说,您需要实现__setitem____delitem__方法来引发异常,因此不能修改列表。在

相关问题 更多 >