title: How do __getitem__, __setitem__, work with slices?
body: <p>I'm running Python 2.7.10.</p>
  
  <p>I need to intercept changes in a list. By "change" I mean anything that modifies the list in the shallow sense (the list is not changed if it consists of the same objects in the same order, regardless of the state of those objects; otherwise, it is). I don't need to find out <strong>how</strong> the list has changed, only that it has. So I just make sure I can detect that, and let the base method do its work. This is my test program:</p>
  
  <pre><code>class List(list):
      def __init__(self, data):
          list.__init__(self, data)
          print '__init__(', data, '):', self
  
      def __getitem__(self, key):
          print 'calling __getitem__(', self, ',', key, ')',
          r = list.__getitem__(self, key)
          print '--&gt;', r
          return r
  
      def __setitem__(self, key, data):
          print 'before __setitem__:', self
          list.__setitem__(self, key, data)
          print 'after  __setitem__(', key, ',', data, '):', self
  
      def __delitem__(self, key):
          print 'before __delitem__:', self
          list.__delitem__(self, key)
          print 'after  __delitem__(', key, '):', self
  
  l = List([0,1,2,3,4,5,6,7]) #1
  x = l[5]                    #2
  l[3] = 33                   #3
  x = l[3:7]                  #4
  del l[3]                    #5
  l[0:4]=[55,66,77,88]        #6
  l.append(8)                 #7
  </code></pre>
  
  <p>Cases #1, #2, #3, and #5 work as I expected; #4, #6, and #7 don't. The program prints:</p>
  
  <pre><code>__init__( [0, 1, 2, 3, 4, 5, 6, 7] ): [0, 1, 2, 3, 4, 5, 6, 7]
  calling __getitem__( [0, 1, 2, 3, 4, 5, 6, 7] , 5 ) --&gt; 5
  before __setitem__: [0, 1, 2, 3, 4, 5, 6, 7]
  after  __setitem__( 3 , 33 ): [0, 1, 2, 33, 4, 5, 6, 7]
  before __delitem__: [0, 1, 2, 33, 4, 5, 6, 7]
  after  __delitem__( 3 ): [0, 1, 2, 4, 5, 6, 7]
  </code></pre>
  
  <p>I'm not terribly surprised by #7: <code>append</code> is probably implemented in an ad-hoc way. But for #4 and #6 I am confused. The <code>__getitem__</code> documentation says: <em>"Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and <strong>slice</strong> objects."</em> (my emphasys). And for <code>__setitem__</code>: <em>" Same note as for <code>__getitem__</code>()"</em>, which I take to mean that <code>key</code> can also be a slice.</p>
  
  <p>What's wrong with my reasoning? I'm prepared, if necessary, to override every list-modifying method (append, extend, insert, pop, etc.), but what should override to catch something like #6?</p>
  
  <p>I am aware of the existence of <code>__setslice__</code>, etc. But those methods are deprecated since 2.0 ...</p>
  
  <p>Hmmm. I read again the docs for <code>__getslice__</code>, <code>__setslice__</code>, etc., and I find this bone-chilling statement:</p>
  
  <p><em>"(However, built-in types in CPython currently still implement <code>__getslice__()</code>. Therefore, you have to override it in derived classes when implementing slicing.)"</em></p>
  
  <p>Is this the explanation? Is this saying "Well, the methods <strong>are</strong> deprecated, but in order to achieve the same functionality in 2.7.10 as you had in 2.0 you still have to override them"? Alas, then why did you deprecate them? How will things work in the future? Is there a "list" class - that I am not aware of - that I could extend and would not present this inconvenience?  What do I really need to override to make sure I catch every list-modifying operation?</p>