How to inherit and extend a list object in Python?

后端 未结 4 1689
盖世英雄少女心
盖世英雄少女心 2020-12-05 04:14

I am interested in using the python list object, but with slightly altered functionality. In particular, I would like the list to be 1-indexed instead of 0-indexed. E.g.:

相关标签:
4条回答
  • 2020-12-05 04:17

    Use the super() function to call the method of the base class, or invoke the method directly:

    class MyList(list):
        def __getitem__(self, key):
            return list.__getitem__(self, key-1)
    

    or

    class MyList(list):
        def __getitem__(self, key):
            return super(MyList, self).__getitem__(key-1)
    

    However, this will not change the behavior of other list methods. For example, index remains unchanged, which can lead to unexpected results:

    numbers = MyList()
    numbers.append("one")
    numbers.append("two")
    
    print numbers.index('one')
    >>> 1
    
    print numbers[numbers.index('one')]
    >>> 'two'
    
    0 讨论(0)
  • 2020-12-05 04:26

    You can avoid violating the Liskov Substitution principle by creating a class that inherits from collections.MutableSequence, which is an abstract class. It would look something like this:

    class MyList(collections.MutableSequence):
    def __init__(self, l=[]):
        if type(l) is not list:
            raise ValueError()
    
        self._inner_list = l
    
    def __len__(self):
        return len(self._inner_list)
    
    def __delitem__(self, index):
        self._inner_list.__delitem__(index - 1)
    
    def insert(self, index, value):
        self._inner_list.insert(index - 1, value)
    
    def __setitem__(self, index, value):
        self._inner_list.__setitem__(index - 1, value)
    
    def __getitem__(self, index):
        return self._inner_list.__getitem__(index - 1)
    

    There is one problem here (though there might be more). If you index your new list like this:

    l = MyList()
    l[0]
    

    you will actually call:

    self._inner_list[-1]
    

    which will get you the last element. So you must do additional checking in the methods and make sure you keep the reverse indexing, if you want to have that feature for your list.

    EDIT:

    Here is the new code, which I believe should not have any problems.

    def indexing_decorator(func):
    
        def decorated(self, index, *args):
            if index == 0:
                raise IndexError('Indices start from 1')
            elif index > 0:
                index -= 1
    
            return func(self, index, *args)
    
        return decorated
    
    
    class MyList(collections.MutableSequence):
        def __init__(self):
            self._inner_list = list()
    
        def __len__(self):
            return len(self._inner_list)
    
        @indexing_decorator
        def __delitem__(self, index):
            self._inner_list.__delitem__(index)
    
        @indexing_decorator
        def insert(self, index, value):
            self._inner_list.insert(index, value)
    
        @indexing_decorator
        def __setitem__(self, index, value):
            self._inner_list.__setitem__(index, value)
    
        @indexing_decorator
        def __getitem__(self, index):
            return self._inner_list.__getitem__(index)
    
        def append(self, value):
            self.insert(len(self) + 1, value)
    
    0 讨论(0)
  • 2020-12-05 04:28
    class ListExt(list):
        def extendX(self, l):
            if l:
                self.extend(l)
    
    0 讨论(0)
  • 2020-12-05 04:32

    Instead, subclass integer using the same method to define all numbers to be minus one from what you set them to. Voila.

    Sorry, I had to. It's like the joke about Microsoft defining dark as the standard.

    0 讨论(0)
提交回复
热议问题