包装Python 2.7中的大列表使其不可变 [英] Wrapping big list in Python 2.7 to make it immutable

查看:76
本文介绍了包装Python 2.7中的大列表使其不可变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个很大的list(> 100k个元素),可以通过函数调用从某个对象中检索它,那么有一种方法可以包装该列表以使其对调用者不可变,而无需将其复制到?

In case I have a really big list (>100k elements) that can be retrieved from some object through function call, is there a way to wrap that list to make it immutable to the caller without copying it to tuple?

在下面的示例中,我只有一个list字段,但是该解决方案应该适用于任意数量的list字段.

In the following example I have only one list field, but the solution should work for any number of list fields.

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]

我会知道如何编写具有这种行为的适配器,但是我对是否已经存在一些我不知道的标准解决方案(例如,在标准库或广为人知的库中)感兴趣.

I would know how to write adapter that behaves that way, but I'm interested if there is already some standard solution (i.e. in standard library or widely known library) I'm not aware of.

推荐答案

不幸的是,标准库(或其他著名的库)中没有这样的包装器.主要原因是list应该是具有索引访问权限的 mutable 序列类型.正如您自己所说的,不可变序列类型将是tuple.因此,通常,使列表不可变的标准方法是通过调用tuple(lst)将其变为元组.

Unfortunately, there is no such wrapper in the standard library (or other prominent libraries). The main reason is that list is supposed to be a mutable sequence type with index access. The immutable sequence type would be a tuple as you already said yourself. So usually, the standard approach to make a list immutable would be to make it into a tuple by calling tuple(lst).

这显然不是您想要的,因为您要避免复制所有元素.因此,您可以创建一个包装列表的自定义类型,并提供所有非修改方法list还支持:

This is obviously not what you want, as you want to avoid to copy all the elements. So instead, you can create a custom type that wraps the list, and offers all non-modifying methods list also supports:

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本身.另一方面,上面的ImmutableList只是一些可索引的序列类型,它恰好包裹了一个真实列表本身.除此之外,将其作为list的子类型实际上将需要您复制一次内容,因此,如果您不想重新创建所有这些项目,那么包装肯定会更好(这似乎是您的要点,否则您可以只需使用tuple).

The alternative would be to subtype list and override __setitem__ and __delitem__ to raise an exception instead, but I would suggest against that, as a subtype of list would be expected to have the same interface as list itself. ImmutableList above on the other hand is just some indexable sequence type which happens to wrap a real list itself. Apart from that, having it as a subtype of list would actually require you to copy the contents once, so wrapping is definitely better if you don’t want to recreate all those items (which seems to be your point—otherwise you could just use tuple).

这篇关于包装Python 2.7中的大列表使其不可变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆