Can I create a "view" on a Python list?
There is no "list slice" class in the Python standard library (nor is one built-in). So, you do need a class, though it need not be big -- especially if you're content with a "readonly" and "compact" slice. E.g.:
import collectionsclass ROListSlice(collections.Sequence): def __init__(self, alist, start, alen): self.alist = alist self.start = start self.alen = alen def __len__(self): return self.alen def adj(self, i): if i<0: i += self.alen return i + self.start def __getitem__(self, i): return self.alist[self.adj(i)]
This has some limitations (doesn't support "slicing a slice") but for most purposes might be OK.
To make this sequence r/w you need to add __setitem__
, __delitem__
, and insert
:
class ListSlice(ROListSlice): def __setitem__(self, i, v): self.alist[self.adj(i)] = v def __delitem__(self, i, v): del self.alist[self.adj(i)] self.alen -= 1 def insert(self, i, v): self.alist.insert(self.adj(i), v) self.alen += 1
Perhaps just use a numpy array:
In [19]: import numpy as npIn [20]: l=np.arange(10)
Basic slicing numpy arrays returns a view, not a copy:
In [21]: lv=l[3:6]In [22]: lvOut[22]: array([3, 4, 5])
Altering l
affects lv
:
In [23]: l[4]=-1In [24]: lvOut[24]: array([ 3, -1, 5])
And altering lv
affects l
:
In [25]: lv[1]=4In [26]: lOut[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
You can do that by creating your own generator using the original list reference.
l = [1,2,3,4,5]lv = (l[i] for i in range(1,4))lv.next() # 2l[2]=-1lv.next() # -1lv.next() # 4
However this being a generator, you can only go through the list once, forwards and it will explode if you remove more elements than you requested with range
.