When inheriting from a parent which has implemented the deprecated __getslice__
, is there any way to get at the original slice before it gets munged?
Here is the example test case, I don't know how to override __getslice__
at a point before the relevant information is already lost. Can it be done instead with monkeypatching? Can it be done via cpython extension?
from unittest import TestCase
from mock import patch
import sys
class BigIntSlicableList(list):
def __getslice__(self, start, stop):
return self[start:stop:None] # force fallback to __getitem__
class BigIntSlicableListTest(TestCase):
@patch.object(BigIntSlicableList, '__getitem__')
def test_slice_big_endpoint(self, mock):
mylist = BigIntSlicableList([1, 2, 3])
start, stop = sys.maxint - 1, sys.maxint + 1
bigint_slice = slice(start, stop)
mylist[start:stop]
mock.assert_called_once_with(bigint_slice)
self.assertEqual(mylist[start:stop], mylist[start:stop:])
Note: I just use list
here as an ssce, I'm not really trying to make a BigList class but wondering how to get around the limitation when a parent class may have already implemented __getslice__
.
The following attempt doesn't work:
class MyList(list):
pass
del MyList.__getslice__
The del statement raises AttributeError
, even though hasattr(MyList, '__getslice__')
returns True.
This question follows on from this one.
You can't, not with a monkeypatch on a type defined in C. That's because list
doesn't have a __getslice__
. It instead fills the sq_slice
slot in the PySequenceMethods
structure. Overriding is allowed, but you cannot make it go away.
Even if you inherited from a Python implementation, monkey patching would come down to deleting the __getslice__
method from the original class.
Your only option is to provide your own version, and that includes the sys.maxsize
limitations. I prefer using a slice()
object for such an override:
def __getslice__(self, start, stop):
return self[slice(start, stop)]
provided the base type knows how to handle a slice
object (which it has to do if it wanted to support strides).
You can avoid the __getslice__
method altogether by using the three-element slice notation or by passing in an explicit slice()
object:
mylist[start:stop:None]
mylist[slice(start, stop)]