Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to mimic a python slice object or subclass?

I would like to include some metadata into a python slice object, along with adding variables to indicate the index of each element in the slice. The metadata is used to label each element that the slice is retrieving. I know there are other labelled data structures that can be used, but in my project slices are predefined as a sort of subscript for numpy arrays and is re-used in various places. So, for me it makes sense to find a way to incorporate this.

I was thinking of sub-classing slice, but apparently it cannot be subclassed which was explained clearly in the answer of the linked question. Has anything changed since then?

What I'd like to do is create a class that looks like:

class Subscript:
    def __init__(self, start, stop, step=None, labels=None):
        self.labels = labels
        self.slc = slice(start, stop, step)

        for i, l in zip(range(start, stop, step), labels):
            setattr(self, l, i)

and be able to use it like this:

sub = Subscript(0, 5, labels=['s0', 's1', 's2', 's3', 's4'])

list(range(10))[sub]  # [0, 1, 2, 3, 4]

range(10)[sub.s0]  # 0

is there a way to do this without having to add a __call__ method to return the slice? Somehow I doubt this because the array or list taking in the sub through __getitem__ wouldn't know what to do with this. I know that I could probably just monkey-patch this information to slice, but am wondering if this type of thing could be done in a class.

Currently, I am defining the slice and slice elements separately like:

sub = slice(0, 5)

s0, s1, s2, s3, s4 = range(5)

But this approach makes it much harder to process the output of multidimensional arrays into a dict where keys are subscript element combinations in the case of more than 1 sub and values are 1d arrays.

like image 330
pbreach Avatar asked Jul 05 '26 20:07

pbreach


1 Answers

Nope, slice objects still can't be sub-classed. I'm saying this based on the flags defined for PySlice_Type in the default Python (3.7) branch:

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */

To allow an object to act as a base class the appropriate Py_TPFLAGS_BASETYPE would be ored in there as they are with types defined allowed to. Taking lists as an example, their flags are defined as:

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
    Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS,         /* tp_flags */

Ignoring the rest, Py_TPFLAGS_BASETYPE is |'ed in there allowing it to act as a base class.

Judging by the fact that I couldn't find this mentioned somewhere in the docs, I'd say it's an implementation detail whose rationale I'm currently not aware of. The only way I believe you might circumvent it is by dropping to C and making your class there.

like image 77
Dimitris Fasarakis Hilliard Avatar answered Jul 07 '26 10:07

Dimitris Fasarakis Hilliard