Make an object that behaves like a slice
<p>How can we make a class represent itself as a slice when appropriate?</p>

<p>This didn't work:</p>

<pre><code>class MyThing(object):
    def __init__(self, start, stop, otherstuff):
        self.start = start
        self.stop = stop
        self.otherstuff = otherstuff
    def __index__(self):
        return slice(self.start, self.stop)
</code></pre>

<p>Expected output:</p>

<pre><code>&gt;&gt;&gt; thing = MyThing(1, 3, 'potato')
&gt;&gt;&gt; 'hello world'[thing]
'el'
</code></pre>

<p>Actual output:</p>

<pre><code>TypeError: __index__ returned non-(int,long) (type slice)
</code></pre>

<p>Inheriting from <code>slice</code> doesn't work either.  </p>

<p>TLDR: It's impossible to make custom classes replace <code>slice</code> for builtins types such as <code>list</code> and <code>tuple</code>.</p>

<hr>

<p>The <code>__index__</code> method exists purely to provide an <em>index</em>, which is by definition an integer in python (see <a href="https://docs.python.org/3.5/reference/datamodel.html#object.__index__" rel="nofollow">the Data Model</a>). You cannot use it for resolving an object to a <code>slice</code>.</p>

<p>I'm afraid that <code>slice</code> seems to be handled specially by python. The interface requires an actual slice; providing its signature (which also includes the <code>indices</code> method) is not sufficient. As you've found out, you cannot inherit from it, so you cannot create new types of <code>slice</code>s. Even Cython will not allow you to inherit from it.</p>

<hr>

<p>So why is <code>slice</code> special? Glad you asked. Welcome to the innards of CPython. Please wash your hands after reading this.</p>

<p>So slice objects are described in <a href="https://raw.githubusercontent.com/python/cpython/c30098c8c6014f3340a369a31df9c74bdbacc269/Doc/c-api/slice.rst" rel="nofollow"><code>slice.rst</code></a>. Note these two guys:</p>

<blockquote>
  <p>.. c:var:: PyTypeObject PySlice_Type</p>
  
  <p>The type object for slice objects.  This is the same as :class:<code>slice</code> in the
     Python layer.</p>
  
  <p>.. c:function:: int PySlice_Check(PyObject *ob)
     Return true if <em>ob</em> is a slice object; <em>ob</em> must not be <em>NULL</em>.</p>
</blockquote>

<p>Now, this is actually implemented in <a href="https://github.com/python/cpython/blob/c30098c8c6014f3340a369a31df9c74bdbacc269/Include/sliceobject.h" rel="nofollow"><code>sliceobject.h</code></a> as :</p>

<pre><code>#define PySlice_Check(op) (Py_TYPE(op) == &amp;PySlice_Type)
</code></pre>

<p>So <em>only</em> the <code>slice</code> type is allowed here. This check is actually used in <a href="https://github.com/python/cpython/blob/c30098c8c6014f3340a369a31df9c74bdbacc269/Objects/listobject.c#L2406" rel="nofollow"><code>list_subscript</code></a> (and <code>tuple subscript</code>, ...) <em>after</em> attempting to use the index protocol (so having <code>__index__</code> on a slice is a bad idea). A custom container class is free to overwrite <code>__getitem__</code> and use its own rules, but that's how <code>list</code> (and <code>tuple</code>, ...) does it.</p>

<p>Now, why is it not possible to subclass <code>slice</code>? Well, <code>type</code> actually has a flag indicating whether something can be subclassed. It is checked <a href="https://github.com/python/cpython/blob/222b935769b07b8e68ec5b0494c39518d90112d1/Objects/typeobject.c#L1971" rel="nofollow">here</a> and generates the error you have seen:</p>

<pre><code>    if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) {
        PyErr_Format(PyExc_TypeError,
                     "type '%.100s' is not an acceptable base type",
                     base_i-&gt;tp_name);
        return NULL;
    }
</code></pre>

<p>I haven't been able to track down how <code>slice</code> (un)sets this value, but the fact that one gets this error means it does. This means you cannot subclass it.</p>

<hr>

<p>Closing remarks: After remembering some long-forgotten C-(non)-skills, I'm fairly sure this is not about optimization in the strict sense. All existing checks and tricks would still work (at least those I've found).</p>

<p>After washing my hands and digging around in the internet, I've found a few references to similar "issues". <a href="http://grokbase.com/t/python/python-list/033r5nks47/type-function-does-not-subtype#20030324rcnwbkfedhzbaf3vmiuer3z4xq" rel="nofollow">Tim Peters has said all there is to say:</a></p>

<blockquote>
  <p>Nothing implemented in C is subclassable unless somebody volunteers the work
  to make it subclassable; nobody volunteered the work to make the <em>[insert name here]</em>
  type subclassable. It sure wasn't at the top of my list <em>wink</em>.</p>
</blockquote>

<p>Also see <a href="http://stackoverflow.com/a/10114382/5349916">this thread</a> for a short discussion on non-subclass'able types.</p>

<p>Practically all alternative interpreters replicate the behavior to various degrees: <a href="https://github.com/nakagami/jython3/blob/master/src/org/python/core/PyType.java#L65" rel="nofollow">Jython</a>, <a href="https://github.com/dropbox/pyston/issues/596" rel="nofollow">Pyston</a>, <a href="https://github.com/IronLanguages/main/blob/eedca3ee3c8260ef205a53c5ee11340b092a250a/Languages/IronPython/IronPython/Runtime/Types/NewTypeInfo.cs#L72" rel="nofollow">IronPython</a> and PyPy (didn't find out how they do it, but they do).</p>

python slice