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