Can I create a “view” on a Python list?











up vote
38
down vote

favorite
10












I have a large list l. I want to create a view from element 4 to 6. I can do it with sequence slice.



>>> l=range(10)
>>> lv=l[3:6]
>>> lv
[3, 4, 5]


However lv is copy of a slice of l. If I change the underlying list, lv does not reflect the change.



>>> l[4] = -1
>>> lv
[3, 4, 5]


Vice versa I want modification on lv reflect in l as well. Other than that the list size are not going to be changed.



I'm not look forward to build a big class to do this. I'm just hoping other Python gurus may know some hidden language trick. Ideally I hope it can like pointer arithmetic in C.



int lv = l + 3;









share|improve this question


















  • 1




    For anybody that comes across this question like I did, memoryview now provides this capability.
    – robert
    Nov 19 '14 at 16:53










  • @robert How? The memoryview works only for objects with buffer interface and list is not one of them.
    – zegkljan
    Dec 7 '14 at 14:08










  • In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
    – robert
    Dec 7 '14 at 14:11










  • The buffer protocol, since the memoryview docs don't link to it.
    – Kevin J. Chase
    Feb 23 '15 at 16:18















up vote
38
down vote

favorite
10












I have a large list l. I want to create a view from element 4 to 6. I can do it with sequence slice.



>>> l=range(10)
>>> lv=l[3:6]
>>> lv
[3, 4, 5]


However lv is copy of a slice of l. If I change the underlying list, lv does not reflect the change.



>>> l[4] = -1
>>> lv
[3, 4, 5]


Vice versa I want modification on lv reflect in l as well. Other than that the list size are not going to be changed.



I'm not look forward to build a big class to do this. I'm just hoping other Python gurus may know some hidden language trick. Ideally I hope it can like pointer arithmetic in C.



int lv = l + 3;









share|improve this question


















  • 1




    For anybody that comes across this question like I did, memoryview now provides this capability.
    – robert
    Nov 19 '14 at 16:53










  • @robert How? The memoryview works only for objects with buffer interface and list is not one of them.
    – zegkljan
    Dec 7 '14 at 14:08










  • In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
    – robert
    Dec 7 '14 at 14:11










  • The buffer protocol, since the memoryview docs don't link to it.
    – Kevin J. Chase
    Feb 23 '15 at 16:18













up vote
38
down vote

favorite
10









up vote
38
down vote

favorite
10






10





I have a large list l. I want to create a view from element 4 to 6. I can do it with sequence slice.



>>> l=range(10)
>>> lv=l[3:6]
>>> lv
[3, 4, 5]


However lv is copy of a slice of l. If I change the underlying list, lv does not reflect the change.



>>> l[4] = -1
>>> lv
[3, 4, 5]


Vice versa I want modification on lv reflect in l as well. Other than that the list size are not going to be changed.



I'm not look forward to build a big class to do this. I'm just hoping other Python gurus may know some hidden language trick. Ideally I hope it can like pointer arithmetic in C.



int lv = l + 3;









share|improve this question













I have a large list l. I want to create a view from element 4 to 6. I can do it with sequence slice.



>>> l=range(10)
>>> lv=l[3:6]
>>> lv
[3, 4, 5]


However lv is copy of a slice of l. If I change the underlying list, lv does not reflect the change.



>>> l[4] = -1
>>> lv
[3, 4, 5]


Vice versa I want modification on lv reflect in l as well. Other than that the list size are not going to be changed.



I'm not look forward to build a big class to do this. I'm just hoping other Python gurus may know some hidden language trick. Ideally I hope it can like pointer arithmetic in C.



int lv = l + 3;






python c arrays list






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Aug 14 '10 at 23:05









Wai Yip Tung

11.9k72945




11.9k72945








  • 1




    For anybody that comes across this question like I did, memoryview now provides this capability.
    – robert
    Nov 19 '14 at 16:53










  • @robert How? The memoryview works only for objects with buffer interface and list is not one of them.
    – zegkljan
    Dec 7 '14 at 14:08










  • In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
    – robert
    Dec 7 '14 at 14:11










  • The buffer protocol, since the memoryview docs don't link to it.
    – Kevin J. Chase
    Feb 23 '15 at 16:18














  • 1




    For anybody that comes across this question like I did, memoryview now provides this capability.
    – robert
    Nov 19 '14 at 16:53










  • @robert How? The memoryview works only for objects with buffer interface and list is not one of them.
    – zegkljan
    Dec 7 '14 at 14:08










  • In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
    – robert
    Dec 7 '14 at 14:11










  • The buffer protocol, since the memoryview docs don't link to it.
    – Kevin J. Chase
    Feb 23 '15 at 16:18








1




1




For anybody that comes across this question like I did, memoryview now provides this capability.
– robert
Nov 19 '14 at 16:53




For anybody that comes across this question like I did, memoryview now provides this capability.
– robert
Nov 19 '14 at 16:53












@robert How? The memoryview works only for objects with buffer interface and list is not one of them.
– zegkljan
Dec 7 '14 at 14:08




@robert How? The memoryview works only for objects with buffer interface and list is not one of them.
– zegkljan
Dec 7 '14 at 14:08












In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
– robert
Dec 7 '14 at 14:11




In the example provided here you should use a bytearray instead of a list. You may also wrap the list in bytearray.
– robert
Dec 7 '14 at 14:11












The buffer protocol, since the memoryview docs don't link to it.
– Kevin J. Chase
Feb 23 '15 at 16:18




The buffer protocol, since the memoryview docs don't link to it.
– Kevin J. Chase
Feb 23 '15 at 16:18












9 Answers
9






active

oldest

votes

















up vote
30
down vote



accepted










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 collections

class 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





share|improve this answer























  • Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
    – Amber
    Aug 14 '10 at 23:34








  • 3




    But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
    – Jochen Ritzel
    Aug 15 '10 at 0:06










  • @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
    – Alex Martelli
    Aug 15 '10 at 0:35






  • 1




    @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
    – Amber
    Aug 15 '10 at 1:06






  • 1




    @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
    – Alex Martelli
    Aug 15 '10 at 1:31


















up vote
28
down vote













Perhaps just use a numpy array:



In [19]: import numpy as np

In [20]: l=np.arange(10)


Basic slicing numpy arrays returns a view, not a copy:



In [21]: lv=l[3:6]

In [22]: lv
Out[22]: array([3, 4, 5])


Altering l affects lv:



In [23]: l[4]=-1

In [24]: lv
Out[24]: array([ 3, -1, 5])


And altering lv affects l:



In [25]: lv[1]=4

In [26]: l
Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])





share|improve this answer




























    up vote
    5
    down vote













    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() # 2
    l[2]=-1
    lv.next() # -1
    lv.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.






    share|improve this answer




























      up vote
      1
      down vote













      Edit: The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - so no, sadly.



      I think buffer type is what you are looking for.



      Pasting example from linked page:



      >>> s = bytearray(1000000)   # a million zeroed bytes
      >>> t = buffer(s, 1) # slice cuts off the first byte
      >>> s[1] = 5 # set the second element in s
      >>> t[0] # which is now also the first element in t!
      'x05'





      share|improve this answer























      • there is no buffer() builtin in Python 3. memoryview() could be used instead.
        – jfs
        Feb 18 '15 at 2:58










      • Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
        – jsbueno
        May 17 '16 at 14:12


















      up vote
      1
      down vote













      As soon as you will take a slice from a list, you will be creating a new list. Ok, it will contain same objects so as long as objects of the list are concerned it would be the same, but if you modify a slice the original list is unchanged.



      If you really want to create a modifiable view, you could imagine a new class based on collection.MutableSequence



      This could be a starting point for a full featured sub list - it correctly processes slice indexes, but at least is lacking specification for negative indexes processing:



      class Sublist(collections.MutableSequence):
      def __init__(self, ls, beg, end):
      self.ls = ls
      self.beg = beg
      self.end = end
      def __getitem__(self, i):
      self._valid(i)
      return self.ls[self._newindex(i)]
      def __delitem__(self, i):
      self._valid(i)
      del self.ls[self._newindex(i)]
      def insert(self, i, x):
      self._valid(i)
      self.ls.insert(i+ self.beg, x)
      def __len__(self):
      return self.end - self.beg
      def __setitem__(self, i, x):
      self.ls[self._newindex(i)] = x
      def _valid(self, i):
      if isinstance(i, slice):
      self._valid(i.start)
      self._valid(i.stop)
      elif isinstance(i, int):
      if i<0 or i>=self.__len__():
      raise IndexError()
      else:
      raise TypeError()
      def _newindex(self, i):
      if isinstance(i, slice):
      return slice(self.beg + i.start, self.beg + i.stop, i.step)
      else:
      return i + self.beg


      Example:



      >>> a = list(range(10))
      >>> s = Sublist(a, 3, 8)
      >>> s[2:4]
      [5, 6]
      >>> s[2] = 15
      >>> a
      [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]





      share|improve this answer





















      • This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
        – Serge Ballesta
        Dec 18 '15 at 17:18


















      up vote
      1
      down vote













      Subclass the more_itertools.SequenceView to affect views by mutating sequences and vice versa.



      Code



      import more_itertools as mit


      class SequenceView(mit.SequenceView):
      """Overload assignments in views."""
      def __setitem__(self, index, item):
      self._target[index] = item


      Demo



      >>> seq = list(range(10))
      >>> view = SequenceView(seq)
      >>> view
      SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

      >>> # Mutate Sequence -> Affect View
      >>> seq[6] = -1
      >>> view[5:8]
      [5, -1, 7]

      >>> # Mutate View -> Affect Sequence
      >>> view[5] = -2
      >>> seq[5:8]
      [-2, -1, 7]


      more_itertools is a third-party library. Install via > pip install more_itertools.






      share|improve this answer

















      • 1




        plus one for making me discover more_itertools, though I won't be using your code
        – loxaxs
        Nov 11 at 14:08










      • No worries. more_itertools is a great toolbox. I encourage people to explore it.
        – pylang
        Nov 12 at 16:59


















      up vote
      1
      down vote













      https://gist.github.com/mathieucaroff/0cf094325fb5294fb54c6a577f05a2c1



      Above link is a solution based on python 3 range ability to be sliced and
      indexed in constant time.



      It supports slicing, equality comparsion, string casting (__str__), and
      reproducers (__repr__), but doesn't support assigment.



      Creating a SliceableSequenceView of a SliceableSequenceView won't slow down
      access times as this case is detected.



      sequenceView.py





      # stackoverflow.com/q/3485475/can-i-create-a-view-on-a-python-list
      try:
      from collections.abc import Sequence
      except ImportError:
      from collections import Sequence # pylint: disable=no-name-in-module

      class SliceableSequenceView(Sequence):
      """
      A read-only sequence which allows slicing without copying the viewed list.
      Supports negative indexes.
      Usage:
      li = list(range(100))
      s = SliceableSequenceView(li)
      u = SliceableSequenceView(li, slice(1,7,2))
      v = s[1:7:2]
      w = s[-99:-93:2]
      li[1] += 10
      assert li[1:7:2] == list(u) == list(v) == list(w)
      """
      __slots__ = "seq range".split()
      def __init__(self, seq, sliced=None):
      """
      Accept any sequence (such as lists, strings or ranges).
      """
      if sliced is None:
      sliced = slice(len(seq))
      l = looksSliceable = True
      l = l and hasattr(seq, "seq") and isinstance(seq.seq, Sequence)
      l = l and hasattr(seq, "range") and isinstance(seq.range, range)
      looksSliceable = l
      if looksSliceable:
      self.seq = seq.seq
      self.range = seq.range[sliced]
      else:
      self.seq = seq
      self.range = range(len(seq))[sliced]

      def __len__(self):
      return len(self.range)

      def __getitem__(self, i):
      if isinstance(i, slice):
      return SliceableSequenceView(self.seq, i)
      return self.seq[self.range[i]]

      def __str__(self):
      r = self.range
      s = slice(r.start, r.stop, r.step)
      return str(self.seq[s])

      def __repr__(self):
      r = self.range
      s = slice(r.start, r.stop, r.step)
      return "SliceableSequenceView({!r})".format(self.seq[s])

      def equal(self, otherSequence):
      if self is otherSequence:
      return True
      if len(self) != len(otherSequence):
      return False
      for v, w in zip(self, otherSequence):
      if v != w:
      print(v, w)
      return False
      return True





      share|improve this answer






























        up vote
        0
        down vote













        You could edit: not do something like



        shiftedlist = type('ShiftedList',
        (list,),
        {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
        )([1, 2, 3, 4, 5, 6])


        Being essentially a one-liner, it's not very Pythonic, but that's the basic gist.



        edit: I've belatedly realized that this doesn't work because list() will essentially do a shallow copy of the list it's passed. So this will end up being more or less the same as just slicing the list. Actually less, due to a missing override of __len__. You'll need to use a proxy class; see Mr. Martelli's answer for the details.






        share|improve this answer






























          up vote
          0
          down vote













          If you are going to be accessing the "view" sequentially then you can just use itertools.islice(..)You can see the documentation for more info.



          l = [1, 2, 3, 4, 5]
          d = [1:3] #[2, 3]
          d = itertools.islice(2, 3) # iterator yielding -> 2, 3


          You can't access individual elements to change them in the slice and if you do change the list you have to re-call isclice(..).






          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f3485475%2fcan-i-create-a-view-on-a-python-list%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            9 Answers
            9






            active

            oldest

            votes








            9 Answers
            9






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            30
            down vote



            accepted










            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 collections

            class 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





            share|improve this answer























            • Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
              – Amber
              Aug 14 '10 at 23:34








            • 3




              But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
              – Jochen Ritzel
              Aug 15 '10 at 0:06










            • @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
              – Alex Martelli
              Aug 15 '10 at 0:35






            • 1




              @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
              – Amber
              Aug 15 '10 at 1:06






            • 1




              @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
              – Alex Martelli
              Aug 15 '10 at 1:31















            up vote
            30
            down vote



            accepted










            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 collections

            class 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





            share|improve this answer























            • Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
              – Amber
              Aug 14 '10 at 23:34








            • 3




              But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
              – Jochen Ritzel
              Aug 15 '10 at 0:06










            • @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
              – Alex Martelli
              Aug 15 '10 at 0:35






            • 1




              @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
              – Amber
              Aug 15 '10 at 1:06






            • 1




              @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
              – Alex Martelli
              Aug 15 '10 at 1:31













            up vote
            30
            down vote



            accepted







            up vote
            30
            down vote



            accepted






            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 collections

            class 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





            share|improve this answer














            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 collections

            class 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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited May 2 '15 at 2:15









            cpburnz

            8,9662074101




            8,9662074101










            answered Aug 14 '10 at 23:11









            Alex Martelli

            614k12410311277




            614k12410311277












            • Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
              – Amber
              Aug 14 '10 at 23:34








            • 3




              But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
              – Jochen Ritzel
              Aug 15 '10 at 0:06










            • @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
              – Alex Martelli
              Aug 15 '10 at 0:35






            • 1




              @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
              – Amber
              Aug 15 '10 at 1:06






            • 1




              @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
              – Alex Martelli
              Aug 15 '10 at 1:31


















            • Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
              – Amber
              Aug 14 '10 at 23:34








            • 3




              But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
              – Jochen Ritzel
              Aug 15 '10 at 0:06










            • @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
              – Alex Martelli
              Aug 15 '10 at 0:35






            • 1




              @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
              – Amber
              Aug 15 '10 at 1:06






            • 1




              @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
              – Alex Martelli
              Aug 15 '10 at 1:31
















            Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
            – Amber
            Aug 14 '10 at 23:34






            Could you do something like def __slice__(self, *args, **kwargs): return (self.alist[self.start:self.start+self.alen]).__slice__(*args, **kwargs) to support things like slicing? Basically passing through the request to a slice created on-demand.
            – Amber
            Aug 14 '10 at 23:34






            3




            3




            But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
            – Jochen Ritzel
            Aug 15 '10 at 0:06




            But if you do alist.insert(0, something) the slice moves! That might or might not be a problem ...
            – Jochen Ritzel
            Aug 15 '10 at 0:06












            @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
            – Alex Martelli
            Aug 15 '10 at 0:35




            @Amber, __slice__ is not a special method in Python. Slicing results in calls to __getindex__, __setindex__, __delindex__, so you'd have to typecheck and adjust that (easier for the getting, as your approach will delegate things OK -- harder for setting and deleting, though).
            – Alex Martelli
            Aug 15 '10 at 0:35




            1




            1




            @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
            – Amber
            Aug 15 '10 at 1:06




            @Alex: Hm. I could have sworn that there were ways to override slicing (say, to allow for things like 2-dimensional slicing). But I could be wrong. :)
            – Amber
            Aug 15 '10 at 1:06




            1




            1




            @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
            – Alex Martelli
            Aug 15 '10 at 1:31




            @Amber, of course you can "override slicing" -- you do that by overriding __getitem__ (and maybe the set and del ones as well, for a type with mutable instances), and type-checking / type-switching on the "index" argument (e.g., to allow a[1:2,3:4], you deal with receiving, as the "index" argument, a tuple with two items, both of them slice objects).
            – Alex Martelli
            Aug 15 '10 at 1:31












            up vote
            28
            down vote













            Perhaps just use a numpy array:



            In [19]: import numpy as np

            In [20]: l=np.arange(10)


            Basic slicing numpy arrays returns a view, not a copy:



            In [21]: lv=l[3:6]

            In [22]: lv
            Out[22]: array([3, 4, 5])


            Altering l affects lv:



            In [23]: l[4]=-1

            In [24]: lv
            Out[24]: array([ 3, -1, 5])


            And altering lv affects l:



            In [25]: lv[1]=4

            In [26]: l
            Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])





            share|improve this answer

























              up vote
              28
              down vote













              Perhaps just use a numpy array:



              In [19]: import numpy as np

              In [20]: l=np.arange(10)


              Basic slicing numpy arrays returns a view, not a copy:



              In [21]: lv=l[3:6]

              In [22]: lv
              Out[22]: array([3, 4, 5])


              Altering l affects lv:



              In [23]: l[4]=-1

              In [24]: lv
              Out[24]: array([ 3, -1, 5])


              And altering lv affects l:



              In [25]: lv[1]=4

              In [26]: l
              Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])





              share|improve this answer























                up vote
                28
                down vote










                up vote
                28
                down vote









                Perhaps just use a numpy array:



                In [19]: import numpy as np

                In [20]: l=np.arange(10)


                Basic slicing numpy arrays returns a view, not a copy:



                In [21]: lv=l[3:6]

                In [22]: lv
                Out[22]: array([3, 4, 5])


                Altering l affects lv:



                In [23]: l[4]=-1

                In [24]: lv
                Out[24]: array([ 3, -1, 5])


                And altering lv affects l:



                In [25]: lv[1]=4

                In [26]: l
                Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])





                share|improve this answer












                Perhaps just use a numpy array:



                In [19]: import numpy as np

                In [20]: l=np.arange(10)


                Basic slicing numpy arrays returns a view, not a copy:



                In [21]: lv=l[3:6]

                In [22]: lv
                Out[22]: array([3, 4, 5])


                Altering l affects lv:



                In [23]: l[4]=-1

                In [24]: lv
                Out[24]: array([ 3, -1, 5])


                And altering lv affects l:



                In [25]: lv[1]=4

                In [26]: l
                Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Aug 14 '10 at 23:25









                unutbu

                538k9911461215




                538k9911461215






















                    up vote
                    5
                    down vote













                    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() # 2
                    l[2]=-1
                    lv.next() # -1
                    lv.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.






                    share|improve this answer

























                      up vote
                      5
                      down vote













                      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() # 2
                      l[2]=-1
                      lv.next() # -1
                      lv.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.






                      share|improve this answer























                        up vote
                        5
                        down vote










                        up vote
                        5
                        down vote









                        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() # 2
                        l[2]=-1
                        lv.next() # -1
                        lv.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.






                        share|improve this answer












                        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() # 2
                        l[2]=-1
                        lv.next() # -1
                        lv.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.







                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered Aug 14 '10 at 23:11









                        viraptor

                        24.2k673146




                        24.2k673146






















                            up vote
                            1
                            down vote













                            Edit: The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - so no, sadly.



                            I think buffer type is what you are looking for.



                            Pasting example from linked page:



                            >>> s = bytearray(1000000)   # a million zeroed bytes
                            >>> t = buffer(s, 1) # slice cuts off the first byte
                            >>> s[1] = 5 # set the second element in s
                            >>> t[0] # which is now also the first element in t!
                            'x05'





                            share|improve this answer























                            • there is no buffer() builtin in Python 3. memoryview() could be used instead.
                              – jfs
                              Feb 18 '15 at 2:58










                            • Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                              – jsbueno
                              May 17 '16 at 14:12















                            up vote
                            1
                            down vote













                            Edit: The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - so no, sadly.



                            I think buffer type is what you are looking for.



                            Pasting example from linked page:



                            >>> s = bytearray(1000000)   # a million zeroed bytes
                            >>> t = buffer(s, 1) # slice cuts off the first byte
                            >>> s[1] = 5 # set the second element in s
                            >>> t[0] # which is now also the first element in t!
                            'x05'





                            share|improve this answer























                            • there is no buffer() builtin in Python 3. memoryview() could be used instead.
                              – jfs
                              Feb 18 '15 at 2:58










                            • Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                              – jsbueno
                              May 17 '16 at 14:12













                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote









                            Edit: The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - so no, sadly.



                            I think buffer type is what you are looking for.



                            Pasting example from linked page:



                            >>> s = bytearray(1000000)   # a million zeroed bytes
                            >>> t = buffer(s, 1) # slice cuts off the first byte
                            >>> s[1] = 5 # set the second element in s
                            >>> t[0] # which is now also the first element in t!
                            'x05'





                            share|improve this answer














                            Edit: The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - so no, sadly.



                            I think buffer type is what you are looking for.



                            Pasting example from linked page:



                            >>> s = bytearray(1000000)   # a million zeroed bytes
                            >>> t = buffer(s, 1) # slice cuts off the first byte
                            >>> s[1] = 5 # set the second element in s
                            >>> t[0] # which is now also the first element in t!
                            'x05'






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited May 23 '17 at 10:31









                            Community

                            11




                            11










                            answered Aug 15 '10 at 0:32









                            cji

                            5,33221515




                            5,33221515












                            • there is no buffer() builtin in Python 3. memoryview() could be used instead.
                              – jfs
                              Feb 18 '15 at 2:58










                            • Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                              – jsbueno
                              May 17 '16 at 14:12


















                            • there is no buffer() builtin in Python 3. memoryview() could be used instead.
                              – jfs
                              Feb 18 '15 at 2:58










                            • Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                              – jsbueno
                              May 17 '16 at 14:12
















                            there is no buffer() builtin in Python 3. memoryview() could be used instead.
                            – jfs
                            Feb 18 '15 at 2:58




                            there is no buffer() builtin in Python 3. memoryview() could be used instead.
                            – jfs
                            Feb 18 '15 at 2:58












                            Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                            – jsbueno
                            May 17 '16 at 14:12




                            Also, this inspects the in memory bytes of the area - Python lists do contain objects (which 'in memory' are pointer to the objects ) so - definetelly, this would be a very wrong approach - One would have to use ctypes , and redo all the Pointer indirection work, as if he was coding in C, that Python does for free
                            – jsbueno
                            May 17 '16 at 14:12










                            up vote
                            1
                            down vote













                            As soon as you will take a slice from a list, you will be creating a new list. Ok, it will contain same objects so as long as objects of the list are concerned it would be the same, but if you modify a slice the original list is unchanged.



                            If you really want to create a modifiable view, you could imagine a new class based on collection.MutableSequence



                            This could be a starting point for a full featured sub list - it correctly processes slice indexes, but at least is lacking specification for negative indexes processing:



                            class Sublist(collections.MutableSequence):
                            def __init__(self, ls, beg, end):
                            self.ls = ls
                            self.beg = beg
                            self.end = end
                            def __getitem__(self, i):
                            self._valid(i)
                            return self.ls[self._newindex(i)]
                            def __delitem__(self, i):
                            self._valid(i)
                            del self.ls[self._newindex(i)]
                            def insert(self, i, x):
                            self._valid(i)
                            self.ls.insert(i+ self.beg, x)
                            def __len__(self):
                            return self.end - self.beg
                            def __setitem__(self, i, x):
                            self.ls[self._newindex(i)] = x
                            def _valid(self, i):
                            if isinstance(i, slice):
                            self._valid(i.start)
                            self._valid(i.stop)
                            elif isinstance(i, int):
                            if i<0 or i>=self.__len__():
                            raise IndexError()
                            else:
                            raise TypeError()
                            def _newindex(self, i):
                            if isinstance(i, slice):
                            return slice(self.beg + i.start, self.beg + i.stop, i.step)
                            else:
                            return i + self.beg


                            Example:



                            >>> a = list(range(10))
                            >>> s = Sublist(a, 3, 8)
                            >>> s[2:4]
                            [5, 6]
                            >>> s[2] = 15
                            >>> a
                            [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]





                            share|improve this answer





















                            • This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                              – Serge Ballesta
                              Dec 18 '15 at 17:18















                            up vote
                            1
                            down vote













                            As soon as you will take a slice from a list, you will be creating a new list. Ok, it will contain same objects so as long as objects of the list are concerned it would be the same, but if you modify a slice the original list is unchanged.



                            If you really want to create a modifiable view, you could imagine a new class based on collection.MutableSequence



                            This could be a starting point for a full featured sub list - it correctly processes slice indexes, but at least is lacking specification for negative indexes processing:



                            class Sublist(collections.MutableSequence):
                            def __init__(self, ls, beg, end):
                            self.ls = ls
                            self.beg = beg
                            self.end = end
                            def __getitem__(self, i):
                            self._valid(i)
                            return self.ls[self._newindex(i)]
                            def __delitem__(self, i):
                            self._valid(i)
                            del self.ls[self._newindex(i)]
                            def insert(self, i, x):
                            self._valid(i)
                            self.ls.insert(i+ self.beg, x)
                            def __len__(self):
                            return self.end - self.beg
                            def __setitem__(self, i, x):
                            self.ls[self._newindex(i)] = x
                            def _valid(self, i):
                            if isinstance(i, slice):
                            self._valid(i.start)
                            self._valid(i.stop)
                            elif isinstance(i, int):
                            if i<0 or i>=self.__len__():
                            raise IndexError()
                            else:
                            raise TypeError()
                            def _newindex(self, i):
                            if isinstance(i, slice):
                            return slice(self.beg + i.start, self.beg + i.stop, i.step)
                            else:
                            return i + self.beg


                            Example:



                            >>> a = list(range(10))
                            >>> s = Sublist(a, 3, 8)
                            >>> s[2:4]
                            [5, 6]
                            >>> s[2] = 15
                            >>> a
                            [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]





                            share|improve this answer





















                            • This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                              – Serge Ballesta
                              Dec 18 '15 at 17:18













                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote









                            As soon as you will take a slice from a list, you will be creating a new list. Ok, it will contain same objects so as long as objects of the list are concerned it would be the same, but if you modify a slice the original list is unchanged.



                            If you really want to create a modifiable view, you could imagine a new class based on collection.MutableSequence



                            This could be a starting point for a full featured sub list - it correctly processes slice indexes, but at least is lacking specification for negative indexes processing:



                            class Sublist(collections.MutableSequence):
                            def __init__(self, ls, beg, end):
                            self.ls = ls
                            self.beg = beg
                            self.end = end
                            def __getitem__(self, i):
                            self._valid(i)
                            return self.ls[self._newindex(i)]
                            def __delitem__(self, i):
                            self._valid(i)
                            del self.ls[self._newindex(i)]
                            def insert(self, i, x):
                            self._valid(i)
                            self.ls.insert(i+ self.beg, x)
                            def __len__(self):
                            return self.end - self.beg
                            def __setitem__(self, i, x):
                            self.ls[self._newindex(i)] = x
                            def _valid(self, i):
                            if isinstance(i, slice):
                            self._valid(i.start)
                            self._valid(i.stop)
                            elif isinstance(i, int):
                            if i<0 or i>=self.__len__():
                            raise IndexError()
                            else:
                            raise TypeError()
                            def _newindex(self, i):
                            if isinstance(i, slice):
                            return slice(self.beg + i.start, self.beg + i.stop, i.step)
                            else:
                            return i + self.beg


                            Example:



                            >>> a = list(range(10))
                            >>> s = Sublist(a, 3, 8)
                            >>> s[2:4]
                            [5, 6]
                            >>> s[2] = 15
                            >>> a
                            [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]





                            share|improve this answer












                            As soon as you will take a slice from a list, you will be creating a new list. Ok, it will contain same objects so as long as objects of the list are concerned it would be the same, but if you modify a slice the original list is unchanged.



                            If you really want to create a modifiable view, you could imagine a new class based on collection.MutableSequence



                            This could be a starting point for a full featured sub list - it correctly processes slice indexes, but at least is lacking specification for negative indexes processing:



                            class Sublist(collections.MutableSequence):
                            def __init__(self, ls, beg, end):
                            self.ls = ls
                            self.beg = beg
                            self.end = end
                            def __getitem__(self, i):
                            self._valid(i)
                            return self.ls[self._newindex(i)]
                            def __delitem__(self, i):
                            self._valid(i)
                            del self.ls[self._newindex(i)]
                            def insert(self, i, x):
                            self._valid(i)
                            self.ls.insert(i+ self.beg, x)
                            def __len__(self):
                            return self.end - self.beg
                            def __setitem__(self, i, x):
                            self.ls[self._newindex(i)] = x
                            def _valid(self, i):
                            if isinstance(i, slice):
                            self._valid(i.start)
                            self._valid(i.stop)
                            elif isinstance(i, int):
                            if i<0 or i>=self.__len__():
                            raise IndexError()
                            else:
                            raise TypeError()
                            def _newindex(self, i):
                            if isinstance(i, slice):
                            return slice(self.beg + i.start, self.beg + i.stop, i.step)
                            else:
                            return i + self.beg


                            Example:



                            >>> a = list(range(10))
                            >>> s = Sublist(a, 3, 8)
                            >>> s[2:4]
                            [5, 6]
                            >>> s[2] = 15
                            >>> a
                            [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Dec 18 '15 at 17:16









                            Serge Ballesta

                            74.7k956128




                            74.7k956128












                            • This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                              – Serge Ballesta
                              Dec 18 '15 at 17:18


















                            • This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                              – Serge Ballesta
                              Dec 18 '15 at 17:18
















                            This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                            – Serge Ballesta
                            Dec 18 '15 at 17:18




                            This is a direct answer to another question that was closed as a duplicate from this one. As other answers from here were relevant, I prefered add it here
                            – Serge Ballesta
                            Dec 18 '15 at 17:18










                            up vote
                            1
                            down vote













                            Subclass the more_itertools.SequenceView to affect views by mutating sequences and vice versa.



                            Code



                            import more_itertools as mit


                            class SequenceView(mit.SequenceView):
                            """Overload assignments in views."""
                            def __setitem__(self, index, item):
                            self._target[index] = item


                            Demo



                            >>> seq = list(range(10))
                            >>> view = SequenceView(seq)
                            >>> view
                            SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

                            >>> # Mutate Sequence -> Affect View
                            >>> seq[6] = -1
                            >>> view[5:8]
                            [5, -1, 7]

                            >>> # Mutate View -> Affect Sequence
                            >>> view[5] = -2
                            >>> seq[5:8]
                            [-2, -1, 7]


                            more_itertools is a third-party library. Install via > pip install more_itertools.






                            share|improve this answer

















                            • 1




                              plus one for making me discover more_itertools, though I won't be using your code
                              – loxaxs
                              Nov 11 at 14:08










                            • No worries. more_itertools is a great toolbox. I encourage people to explore it.
                              – pylang
                              Nov 12 at 16:59















                            up vote
                            1
                            down vote













                            Subclass the more_itertools.SequenceView to affect views by mutating sequences and vice versa.



                            Code



                            import more_itertools as mit


                            class SequenceView(mit.SequenceView):
                            """Overload assignments in views."""
                            def __setitem__(self, index, item):
                            self._target[index] = item


                            Demo



                            >>> seq = list(range(10))
                            >>> view = SequenceView(seq)
                            >>> view
                            SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

                            >>> # Mutate Sequence -> Affect View
                            >>> seq[6] = -1
                            >>> view[5:8]
                            [5, -1, 7]

                            >>> # Mutate View -> Affect Sequence
                            >>> view[5] = -2
                            >>> seq[5:8]
                            [-2, -1, 7]


                            more_itertools is a third-party library. Install via > pip install more_itertools.






                            share|improve this answer

















                            • 1




                              plus one for making me discover more_itertools, though I won't be using your code
                              – loxaxs
                              Nov 11 at 14:08










                            • No worries. more_itertools is a great toolbox. I encourage people to explore it.
                              – pylang
                              Nov 12 at 16:59













                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote









                            Subclass the more_itertools.SequenceView to affect views by mutating sequences and vice versa.



                            Code



                            import more_itertools as mit


                            class SequenceView(mit.SequenceView):
                            """Overload assignments in views."""
                            def __setitem__(self, index, item):
                            self._target[index] = item


                            Demo



                            >>> seq = list(range(10))
                            >>> view = SequenceView(seq)
                            >>> view
                            SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

                            >>> # Mutate Sequence -> Affect View
                            >>> seq[6] = -1
                            >>> view[5:8]
                            [5, -1, 7]

                            >>> # Mutate View -> Affect Sequence
                            >>> view[5] = -2
                            >>> seq[5:8]
                            [-2, -1, 7]


                            more_itertools is a third-party library. Install via > pip install more_itertools.






                            share|improve this answer












                            Subclass the more_itertools.SequenceView to affect views by mutating sequences and vice versa.



                            Code



                            import more_itertools as mit


                            class SequenceView(mit.SequenceView):
                            """Overload assignments in views."""
                            def __setitem__(self, index, item):
                            self._target[index] = item


                            Demo



                            >>> seq = list(range(10))
                            >>> view = SequenceView(seq)
                            >>> view
                            SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

                            >>> # Mutate Sequence -> Affect View
                            >>> seq[6] = -1
                            >>> view[5:8]
                            [5, -1, 7]

                            >>> # Mutate View -> Affect Sequence
                            >>> view[5] = -2
                            >>> seq[5:8]
                            [-2, -1, 7]


                            more_itertools is a third-party library. Install via > pip install more_itertools.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Feb 14 at 3:21









                            pylang

                            12.8k23551




                            12.8k23551








                            • 1




                              plus one for making me discover more_itertools, though I won't be using your code
                              – loxaxs
                              Nov 11 at 14:08










                            • No worries. more_itertools is a great toolbox. I encourage people to explore it.
                              – pylang
                              Nov 12 at 16:59














                            • 1




                              plus one for making me discover more_itertools, though I won't be using your code
                              – loxaxs
                              Nov 11 at 14:08










                            • No worries. more_itertools is a great toolbox. I encourage people to explore it.
                              – pylang
                              Nov 12 at 16:59








                            1




                            1




                            plus one for making me discover more_itertools, though I won't be using your code
                            – loxaxs
                            Nov 11 at 14:08




                            plus one for making me discover more_itertools, though I won't be using your code
                            – loxaxs
                            Nov 11 at 14:08












                            No worries. more_itertools is a great toolbox. I encourage people to explore it.
                            – pylang
                            Nov 12 at 16:59




                            No worries. more_itertools is a great toolbox. I encourage people to explore it.
                            – pylang
                            Nov 12 at 16:59










                            up vote
                            1
                            down vote













                            https://gist.github.com/mathieucaroff/0cf094325fb5294fb54c6a577f05a2c1



                            Above link is a solution based on python 3 range ability to be sliced and
                            indexed in constant time.



                            It supports slicing, equality comparsion, string casting (__str__), and
                            reproducers (__repr__), but doesn't support assigment.



                            Creating a SliceableSequenceView of a SliceableSequenceView won't slow down
                            access times as this case is detected.



                            sequenceView.py





                            # stackoverflow.com/q/3485475/can-i-create-a-view-on-a-python-list
                            try:
                            from collections.abc import Sequence
                            except ImportError:
                            from collections import Sequence # pylint: disable=no-name-in-module

                            class SliceableSequenceView(Sequence):
                            """
                            A read-only sequence which allows slicing without copying the viewed list.
                            Supports negative indexes.
                            Usage:
                            li = list(range(100))
                            s = SliceableSequenceView(li)
                            u = SliceableSequenceView(li, slice(1,7,2))
                            v = s[1:7:2]
                            w = s[-99:-93:2]
                            li[1] += 10
                            assert li[1:7:2] == list(u) == list(v) == list(w)
                            """
                            __slots__ = "seq range".split()
                            def __init__(self, seq, sliced=None):
                            """
                            Accept any sequence (such as lists, strings or ranges).
                            """
                            if sliced is None:
                            sliced = slice(len(seq))
                            l = looksSliceable = True
                            l = l and hasattr(seq, "seq") and isinstance(seq.seq, Sequence)
                            l = l and hasattr(seq, "range") and isinstance(seq.range, range)
                            looksSliceable = l
                            if looksSliceable:
                            self.seq = seq.seq
                            self.range = seq.range[sliced]
                            else:
                            self.seq = seq
                            self.range = range(len(seq))[sliced]

                            def __len__(self):
                            return len(self.range)

                            def __getitem__(self, i):
                            if isinstance(i, slice):
                            return SliceableSequenceView(self.seq, i)
                            return self.seq[self.range[i]]

                            def __str__(self):
                            r = self.range
                            s = slice(r.start, r.stop, r.step)
                            return str(self.seq[s])

                            def __repr__(self):
                            r = self.range
                            s = slice(r.start, r.stop, r.step)
                            return "SliceableSequenceView({!r})".format(self.seq[s])

                            def equal(self, otherSequence):
                            if self is otherSequence:
                            return True
                            if len(self) != len(otherSequence):
                            return False
                            for v, w in zip(self, otherSequence):
                            if v != w:
                            print(v, w)
                            return False
                            return True





                            share|improve this answer



























                              up vote
                              1
                              down vote













                              https://gist.github.com/mathieucaroff/0cf094325fb5294fb54c6a577f05a2c1



                              Above link is a solution based on python 3 range ability to be sliced and
                              indexed in constant time.



                              It supports slicing, equality comparsion, string casting (__str__), and
                              reproducers (__repr__), but doesn't support assigment.



                              Creating a SliceableSequenceView of a SliceableSequenceView won't slow down
                              access times as this case is detected.



                              sequenceView.py





                              # stackoverflow.com/q/3485475/can-i-create-a-view-on-a-python-list
                              try:
                              from collections.abc import Sequence
                              except ImportError:
                              from collections import Sequence # pylint: disable=no-name-in-module

                              class SliceableSequenceView(Sequence):
                              """
                              A read-only sequence which allows slicing without copying the viewed list.
                              Supports negative indexes.
                              Usage:
                              li = list(range(100))
                              s = SliceableSequenceView(li)
                              u = SliceableSequenceView(li, slice(1,7,2))
                              v = s[1:7:2]
                              w = s[-99:-93:2]
                              li[1] += 10
                              assert li[1:7:2] == list(u) == list(v) == list(w)
                              """
                              __slots__ = "seq range".split()
                              def __init__(self, seq, sliced=None):
                              """
                              Accept any sequence (such as lists, strings or ranges).
                              """
                              if sliced is None:
                              sliced = slice(len(seq))
                              l = looksSliceable = True
                              l = l and hasattr(seq, "seq") and isinstance(seq.seq, Sequence)
                              l = l and hasattr(seq, "range") and isinstance(seq.range, range)
                              looksSliceable = l
                              if looksSliceable:
                              self.seq = seq.seq
                              self.range = seq.range[sliced]
                              else:
                              self.seq = seq
                              self.range = range(len(seq))[sliced]

                              def __len__(self):
                              return len(self.range)

                              def __getitem__(self, i):
                              if isinstance(i, slice):
                              return SliceableSequenceView(self.seq, i)
                              return self.seq[self.range[i]]

                              def __str__(self):
                              r = self.range
                              s = slice(r.start, r.stop, r.step)
                              return str(self.seq[s])

                              def __repr__(self):
                              r = self.range
                              s = slice(r.start, r.stop, r.step)
                              return "SliceableSequenceView({!r})".format(self.seq[s])

                              def equal(self, otherSequence):
                              if self is otherSequence:
                              return True
                              if len(self) != len(otherSequence):
                              return False
                              for v, w in zip(self, otherSequence):
                              if v != w:
                              print(v, w)
                              return False
                              return True





                              share|improve this answer

























                                up vote
                                1
                                down vote










                                up vote
                                1
                                down vote









                                https://gist.github.com/mathieucaroff/0cf094325fb5294fb54c6a577f05a2c1



                                Above link is a solution based on python 3 range ability to be sliced and
                                indexed in constant time.



                                It supports slicing, equality comparsion, string casting (__str__), and
                                reproducers (__repr__), but doesn't support assigment.



                                Creating a SliceableSequenceView of a SliceableSequenceView won't slow down
                                access times as this case is detected.



                                sequenceView.py





                                # stackoverflow.com/q/3485475/can-i-create-a-view-on-a-python-list
                                try:
                                from collections.abc import Sequence
                                except ImportError:
                                from collections import Sequence # pylint: disable=no-name-in-module

                                class SliceableSequenceView(Sequence):
                                """
                                A read-only sequence which allows slicing without copying the viewed list.
                                Supports negative indexes.
                                Usage:
                                li = list(range(100))
                                s = SliceableSequenceView(li)
                                u = SliceableSequenceView(li, slice(1,7,2))
                                v = s[1:7:2]
                                w = s[-99:-93:2]
                                li[1] += 10
                                assert li[1:7:2] == list(u) == list(v) == list(w)
                                """
                                __slots__ = "seq range".split()
                                def __init__(self, seq, sliced=None):
                                """
                                Accept any sequence (such as lists, strings or ranges).
                                """
                                if sliced is None:
                                sliced = slice(len(seq))
                                l = looksSliceable = True
                                l = l and hasattr(seq, "seq") and isinstance(seq.seq, Sequence)
                                l = l and hasattr(seq, "range") and isinstance(seq.range, range)
                                looksSliceable = l
                                if looksSliceable:
                                self.seq = seq.seq
                                self.range = seq.range[sliced]
                                else:
                                self.seq = seq
                                self.range = range(len(seq))[sliced]

                                def __len__(self):
                                return len(self.range)

                                def __getitem__(self, i):
                                if isinstance(i, slice):
                                return SliceableSequenceView(self.seq, i)
                                return self.seq[self.range[i]]

                                def __str__(self):
                                r = self.range
                                s = slice(r.start, r.stop, r.step)
                                return str(self.seq[s])

                                def __repr__(self):
                                r = self.range
                                s = slice(r.start, r.stop, r.step)
                                return "SliceableSequenceView({!r})".format(self.seq[s])

                                def equal(self, otherSequence):
                                if self is otherSequence:
                                return True
                                if len(self) != len(otherSequence):
                                return False
                                for v, w in zip(self, otherSequence):
                                if v != w:
                                print(v, w)
                                return False
                                return True





                                share|improve this answer














                                https://gist.github.com/mathieucaroff/0cf094325fb5294fb54c6a577f05a2c1



                                Above link is a solution based on python 3 range ability to be sliced and
                                indexed in constant time.



                                It supports slicing, equality comparsion, string casting (__str__), and
                                reproducers (__repr__), but doesn't support assigment.



                                Creating a SliceableSequenceView of a SliceableSequenceView won't slow down
                                access times as this case is detected.



                                sequenceView.py





                                # stackoverflow.com/q/3485475/can-i-create-a-view-on-a-python-list
                                try:
                                from collections.abc import Sequence
                                except ImportError:
                                from collections import Sequence # pylint: disable=no-name-in-module

                                class SliceableSequenceView(Sequence):
                                """
                                A read-only sequence which allows slicing without copying the viewed list.
                                Supports negative indexes.
                                Usage:
                                li = list(range(100))
                                s = SliceableSequenceView(li)
                                u = SliceableSequenceView(li, slice(1,7,2))
                                v = s[1:7:2]
                                w = s[-99:-93:2]
                                li[1] += 10
                                assert li[1:7:2] == list(u) == list(v) == list(w)
                                """
                                __slots__ = "seq range".split()
                                def __init__(self, seq, sliced=None):
                                """
                                Accept any sequence (such as lists, strings or ranges).
                                """
                                if sliced is None:
                                sliced = slice(len(seq))
                                l = looksSliceable = True
                                l = l and hasattr(seq, "seq") and isinstance(seq.seq, Sequence)
                                l = l and hasattr(seq, "range") and isinstance(seq.range, range)
                                looksSliceable = l
                                if looksSliceable:
                                self.seq = seq.seq
                                self.range = seq.range[sliced]
                                else:
                                self.seq = seq
                                self.range = range(len(seq))[sliced]

                                def __len__(self):
                                return len(self.range)

                                def __getitem__(self, i):
                                if isinstance(i, slice):
                                return SliceableSequenceView(self.seq, i)
                                return self.seq[self.range[i]]

                                def __str__(self):
                                r = self.range
                                s = slice(r.start, r.stop, r.step)
                                return str(self.seq[s])

                                def __repr__(self):
                                r = self.range
                                s = slice(r.start, r.stop, r.step)
                                return "SliceableSequenceView({!r})".format(self.seq[s])

                                def equal(self, otherSequence):
                                if self is otherSequence:
                                return True
                                if len(self) != len(otherSequence):
                                return False
                                for v, w in zip(self, otherSequence):
                                if v != w:
                                print(v, w)
                                return False
                                return True






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Nov 17 at 11:09

























                                answered Nov 11 at 20:53









                                Mathieu CAROFF

                                3267




                                3267






















                                    up vote
                                    0
                                    down vote













                                    You could edit: not do something like



                                    shiftedlist = type('ShiftedList',
                                    (list,),
                                    {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
                                    )([1, 2, 3, 4, 5, 6])


                                    Being essentially a one-liner, it's not very Pythonic, but that's the basic gist.



                                    edit: I've belatedly realized that this doesn't work because list() will essentially do a shallow copy of the list it's passed. So this will end up being more or less the same as just slicing the list. Actually less, due to a missing override of __len__. You'll need to use a proxy class; see Mr. Martelli's answer for the details.






                                    share|improve this answer



























                                      up vote
                                      0
                                      down vote













                                      You could edit: not do something like



                                      shiftedlist = type('ShiftedList',
                                      (list,),
                                      {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
                                      )([1, 2, 3, 4, 5, 6])


                                      Being essentially a one-liner, it's not very Pythonic, but that's the basic gist.



                                      edit: I've belatedly realized that this doesn't work because list() will essentially do a shallow copy of the list it's passed. So this will end up being more or less the same as just slicing the list. Actually less, due to a missing override of __len__. You'll need to use a proxy class; see Mr. Martelli's answer for the details.






                                      share|improve this answer

























                                        up vote
                                        0
                                        down vote










                                        up vote
                                        0
                                        down vote









                                        You could edit: not do something like



                                        shiftedlist = type('ShiftedList',
                                        (list,),
                                        {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
                                        )([1, 2, 3, 4, 5, 6])


                                        Being essentially a one-liner, it's not very Pythonic, but that's the basic gist.



                                        edit: I've belatedly realized that this doesn't work because list() will essentially do a shallow copy of the list it's passed. So this will end up being more or less the same as just slicing the list. Actually less, due to a missing override of __len__. You'll need to use a proxy class; see Mr. Martelli's answer for the details.






                                        share|improve this answer














                                        You could edit: not do something like



                                        shiftedlist = type('ShiftedList',
                                        (list,),
                                        {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
                                        )([1, 2, 3, 4, 5, 6])


                                        Being essentially a one-liner, it's not very Pythonic, but that's the basic gist.



                                        edit: I've belatedly realized that this doesn't work because list() will essentially do a shallow copy of the list it's passed. So this will end up being more or less the same as just slicing the list. Actually less, due to a missing override of __len__. You'll need to use a proxy class; see Mr. Martelli's answer for the details.







                                        share|improve this answer














                                        share|improve this answer



                                        share|improve this answer








                                        edited May 23 '17 at 12:02









                                        Community

                                        11




                                        11










                                        answered Aug 14 '10 at 23:16









                                        intuited

                                        15k44873




                                        15k44873






















                                            up vote
                                            0
                                            down vote













                                            If you are going to be accessing the "view" sequentially then you can just use itertools.islice(..)You can see the documentation for more info.



                                            l = [1, 2, 3, 4, 5]
                                            d = [1:3] #[2, 3]
                                            d = itertools.islice(2, 3) # iterator yielding -> 2, 3


                                            You can't access individual elements to change them in the slice and if you do change the list you have to re-call isclice(..).






                                            share|improve this answer

























                                              up vote
                                              0
                                              down vote













                                              If you are going to be accessing the "view" sequentially then you can just use itertools.islice(..)You can see the documentation for more info.



                                              l = [1, 2, 3, 4, 5]
                                              d = [1:3] #[2, 3]
                                              d = itertools.islice(2, 3) # iterator yielding -> 2, 3


                                              You can't access individual elements to change them in the slice and if you do change the list you have to re-call isclice(..).






                                              share|improve this answer























                                                up vote
                                                0
                                                down vote










                                                up vote
                                                0
                                                down vote









                                                If you are going to be accessing the "view" sequentially then you can just use itertools.islice(..)You can see the documentation for more info.



                                                l = [1, 2, 3, 4, 5]
                                                d = [1:3] #[2, 3]
                                                d = itertools.islice(2, 3) # iterator yielding -> 2, 3


                                                You can't access individual elements to change them in the slice and if you do change the list you have to re-call isclice(..).






                                                share|improve this answer












                                                If you are going to be accessing the "view" sequentially then you can just use itertools.islice(..)You can see the documentation for more info.



                                                l = [1, 2, 3, 4, 5]
                                                d = [1:3] #[2, 3]
                                                d = itertools.islice(2, 3) # iterator yielding -> 2, 3


                                                You can't access individual elements to change them in the slice and if you do change the list you have to re-call isclice(..).







                                                share|improve this answer












                                                share|improve this answer



                                                share|improve this answer










                                                answered Aug 12 '16 at 12:43









                                                Adam Gillessen

                                                1




                                                1






























                                                    draft saved

                                                    draft discarded




















































                                                    Thanks for contributing an answer to Stack Overflow!


                                                    • Please be sure to answer the question. Provide details and share your research!

                                                    But avoid



                                                    • Asking for help, clarification, or responding to other answers.

                                                    • Making statements based on opinion; back them up with references or personal experience.


                                                    To learn more, see our tips on writing great answers.





                                                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                                    Please pay close attention to the following guidance:


                                                    • Please be sure to answer the question. Provide details and share your research!

                                                    But avoid



                                                    • Asking for help, clarification, or responding to other answers.

                                                    • Making statements based on opinion; back them up with references or personal experience.


                                                    To learn more, see our tips on writing great answers.




                                                    draft saved


                                                    draft discarded














                                                    StackExchange.ready(
                                                    function () {
                                                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f3485475%2fcan-i-create-a-view-on-a-python-list%23new-answer', 'question_page');
                                                    }
                                                    );

                                                    Post as a guest















                                                    Required, but never shown





















































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown

































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown







                                                    Popular posts from this blog

                                                    Bressuire

                                                    Vorschmack

                                                    Quarantine