Wrapping big list in Python 2.7 to make it immutable
immutability, list, python, wrapper
Solution
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)`.
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
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`).
Problem
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`? 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.