Skip to content
Advertisement

making list index possible for python class list

Python has no function for list index argument in __getitem()__, __setitem()__, __delitem()__. Since I have been an R user for long time, it looks quite natural to utilize list index. I know there is pandas or numpy but it is cumbersome to change the type. AND IT NEEDS IMPORTING EXTRA PACKAGE!

>>> import numpy as np
>>> lst = [1,2,3,4,5]
>>> np.array(lst)[[0,3,4]]
array([1, 4, 5])

Here is my proposal.

class list2(__builtins__.list):
    def __getitem__(self, x):
        if isinstance(x, __builtins__.list):
            #print(x)
            return [__builtins__.list.__getitem__(self, y) for y in x]
        else:
            return __builtins__.list.__getitem__(self,x)
    def __setitem__(self, index, elem):
        if isinstance(index, __builtins__.list):
            if isinstance(elem, __builtins__.list):
                for i,x in zip(index, elem):
                    __builtins__.list.__setitem__(self, i, x)
            else:
                for i in index:
                    __builtins__.list.__setitem__(self, i, elem)
                #self[i] = x
        else:
            __builtins__.list.__setitem__(self, index, elem)
    def __delitem__(self, index):
        if isinstance(index, __builtins__.list):
            for i in sorted(index, reverse = True):
                __builtins__.list.__delitem__(self, i)
                #self[i] = x
        else:
            __builtins__.list.__delitem__(self, index)

It seems to work okay.

>>> l = list2(['a', 'b', 'c', 'd', 'e'])
>>> l[[2,3]]
['c', 'd']
>>> l[[2,3]]= ['-', '-']
>>> l
['a', 'b', '-', '-', 'e']
>>> del l[[0,3]]
>>> l
['b', '-', 'e']

But is there any pitfall? or is there any part that needs to be improved?

Advertisement

Answer

The main pitfall with something like this is that it’s ‘astonishing’, which is generally frowned upon in Python – we expect the default list to behave like the default list.

Aside from that, your implementation mostly looks complete to me. There are maybe a couple of issues:

  • What happens if we use __setitem__ or __delitem__ and list the same index more than once?
  • What happens if we give __setitem__ lists with mismatched lengths?

There’s one key thing that I think it would be worth changing: get rid of lists of indexes, and use tuples instead.

If you pass a comma separated list of indices to __getitem__, these are actually parsed as a tuple!

>>> class Thing:
...     def __getitem__(self, indices):
...         print(indices)
...
>>> t = Thing()
>>> t[1, 2, 3]
(1, 2, 3)

So, rather than using lists, expect tuples and ditch the double brackets.

In terms of other improvements, it’s probably better to get rid of the references to __builtins__, and use super() to access the functions from the default list implementation, and it’s a good idea to add a custom __repr__ so we don’t mix this up with the default list.

If you add all of these suggestions, it would look something like this (typing added for clarity):

from typing import Any, Tuple, Union

class list2(list):
    def __getitem__(self, index: Union[int, Tuple[int], slice]) -> Any:
        if isinstance(index, (slice, int)):
            return super().__getitem__(index)

        return [super(list2, self).__getitem__(x) for x in index]

    def __setitem__(self, index: Union[int, Tuple[int], slice], elem: Any):
        if isinstance(index, (slice, int)):
            return super().__setitem__(index, elem)

        if len(index) != len(elem):
            raise ValueError("Number of elements in index does not match element.")

        for x, element in zip(index, elem):
            self[x] = element

    def __delitem__(self, index: Union[int, Tuple[int], slice]):
        if isinstance(index, (slice, int)):
            return super().__delitem__(index)

        for x in sorted(set(index), reverse=True):
            super().__delitem__(x)

    def __repr__(self) -> str:
        return f"list2({super().__repr__()})"

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement