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.
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.
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.
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.
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 slice
s. 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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With