Search code examples
pythonpython-3.xslicemagic-methods

__getitem__ method receives int instead of slice obj


When implementing the __getitem__ method in a custom class I expect the second argument to always be a slice obj.

However, when one execute obj[i] where i is an integer, obj.__getitem__(self,value) receives an int instead of a slice.

This can be tested doing

class MyClass:

    def __getitem__(self, sliceobj):
        print(type(sliceobj))

a = MyClass()

a[1:5]
a[2:]
a[::2]
a[0]

>> <class 'slice'>
>> <class 'slice'>
>> <class 'slice'>
>> <class 'int'>

This is causing me issues as my class has an internal list (defined in __init__) and I want to use the slice to iterate over it. The problem is that the output of list[slice] is not an iterable when slice is an int.

In other words:

class MyClass2:

    def __getitem__(self, sliceobj):

        a_list = [1,2,3,4]

        print(sliceobj)

        for val in a_list[sliceobj]:
            # do stuff
            pass

        print('it worked')

a = MyClass2()

a[1:3]
a[2:]
a[::2]
a[0]

works for the first 3 calls, but it doesn't for the last, as a_list[0] is not iterable.

Shouldn't a[0] be translated in a.__getitem__(slice(0,1)) (that would work) ?


Solution

  • As per the docs:

    For sequence types, the accepted keys should be integers and slice objects

    You can check if the key is a slice or not and create one:

    class MyClass2:
        def __getitem__(self, key):
    
            a_list = [1,2,3,4]
            keys_to_iterate = key if isinstance(key, slice) else slice(key, key+1)
            print(key)
    
            for val in a_list[keys_to_iterate]:
                # do stuff
                pass
    
            print('it worked')
    

    Running example: https://repl.it/repls/SmallDarkblueWifi