Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make an object that behaves like a slice

Tags:

python

slice

How can we make a class represent itself as a slice when appropriate?

This didn't work:

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)

Expected output:

>>> thing = MyThing(1, 3, 'potato')
>>> 'hello world'[thing]
'el'

Actual output:

TypeError: __index__ returned non-(int,long) (type slice)

Inheriting from slice doesn't work either.

like image 423
wim Avatar asked Oct 11 '16 05:10

wim


People also ask

How do you slice an object in TypeScript?

In TypeScript the slice() method returns a new array that starts with the index given by the first parameter and continuing for the number of elements given by the second parameter. The slice and concat methods let you create a new array from part of or all of an array.

How do you use slice function?

Definition and Usage The slice() function returns a slice object. A slice object is used to specify how to slice a sequence. You can specify where to start the slicing, and where to end. You can also specify the step, which allows you to e.g. slice only every other item.

Is slicing possible in set?

Practical Data Science using Python The elements in the set are immutable(cannot be modified) but the set as a whole is mutable. There is no index attached to any element in a python set. So they do not support any indexing or slicing operation.


1 Answers

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


The __index__ method exists purely to provide an index, which is by definition an integer in python (see the Data Model). You cannot use it for resolving an object to a slice.

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


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

So slice objects are described in slice.rst. Note these two guys:

.. c:var:: PyTypeObject PySlice_Type

The type object for slice objects. This is the same as :class:slice in the Python layer.

.. c:function:: int PySlice_Check(PyObject *ob) Return true if ob is a slice object; ob must not be NULL.

Now, this is actually implemented in sliceobject.h as :

#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type)

So only the slice type is allowed here. This check is actually used in list_subscript (and tuple subscript, ...) after attempting to use the index protocol (so having __index__ on a slice is a bad idea). A custom container class is free to overwrite __getitem__ and use its own rules, but that's how list (and tuple, ...) does it.

Now, why is it not possible to subclass slice? Well, type actually has a flag indicating whether something can be subclassed. It is checked here and generates the error you have seen:

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

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


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).

After washing my hands and digging around in the internet, I've found a few references to similar "issues". Tim Peters has said all there is to say:

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

Also see this thread for a short discussion on non-subclass'able types.

Practically all alternative interpreters replicate the behavior to various degrees: Jython, Pyston, IronPython and PyPy (didn't find out how they do it, but they do).

like image 105
MisterMiyagi Avatar answered Sep 21 '22 12:09

MisterMiyagi