3.3.6 Additional methods for emulation of sequence types

##
3.3.6 Additional methods for emulation of sequence types

The following optional methods can be defined to further emulate sequence objects. Immutable sequences methods should at most only define `__getslice__()`; mutable sequences might define all three methods.

`__getslice__`( | self, i, j)

  Deprecated since release 2.0. Support slice objects as parameters to the `__getitem__()` method.

  Called to implement evaluation of `self[i:j]`. The returned object should be of the same type as self. Note that missing i or j in the slice expression are replaced by zero or `sys.maxint`, respectively. If negative indexes are used in the slice, the length of the sequence is added to that index. If the instance does not implement the `__len__()` method, an `AttributeError` is raised. No guarantee is made that indexes adjusted this way are not still negative. Indexes which are greater than the length of the sequence are not modified. If no `__getslice__()` is found, a slice object is created instead, and passed to `__getitem__()` instead.

`__setslice__`( | self, i, j, sequence)

  Called to implement assignment to `self[i:j]`. Same notes for i and j as for `__getslice__()`.

  This method is deprecated. If no `__setslice__()` is found, or for extended slicing of the form `self[i:j:k]`, a slice object is created, and passed to `__setitem__()`, instead of `__setslice__()` being called.

`__delslice__`( | self, i, j)

  Called to implement deletion of `self[i:j]`. Same notes for i and j as for `__getslice__()`. This method is deprecated. If no `__delslice__()` is found, or for extended slicing of the form `self[i:j:k]`, a slice object is created, and passed to `__delitem__()`, instead of `__delslice__()` being called.

Notice that these methods are only invoked when a single slice with a single colon is used, and the slice method is available. For slice operations involving extended slice notation, or in absence of the slice methods, `__getitem__()`, `__setitem__()` or `__delitem__()` is called with a slice object as argument.

The following example demonstrate how to make your program or module compatible with earlier versions of Python (assuming that methods `__getitem__()`, `__setitem__()` and `__delitem__()` support slice objects as arguments):

    class MyClass:
        ...
        def __getitem__(self, index):
            ...
        def __setitem__(self, index, value):
            ...
        def __delitem__(self, index):
            ...

        if sys.version_info < (2, 0):
            # They won't be defined if version is at least 2.0 final

            def __getslice__(self, i, j):
                return self[max(0, i):max(0, j):]
            def __setslice__(self, i, j, seq):
                self[max(0, i):max(0, j):] = seq
            def __delslice__(self, i, j):
                del self[max(0, i):max(0, j):]
        ...

Note the calls to `max()`; these are necessary because of the handling of negative indices before the `__*slice__()` methods are called. When negative indexes are used, the `__*item__()` methods receive them as provided, but the `__*slice__()` methods get a ``cooked'' form of the index values. For each negative index value, the length of the sequence is added to the index before calling the method (which may still result in a negative index); this is the customary handling of negative indexes by the built-in sequence types, and the `__*item__()` methods are expected to do this as well. However, since they should already be doing that, negative indexes cannot be passed in; they must be constrained to the bounds of the sequence before being passed to the `__*item__()` methods. Calling `max(0, i)` conveniently returns the proper value.