Подтвердить что ты не робот

Как наследовать и расширять объект списка в Python?

Я заинтересован в использовании объекта списка python, но с немного измененной функциональностью. В частности, я хотел бы, чтобы список был 1-индексированным, а не 0-индексированным. Например:.

>> mylist = MyList()
>> mylist.extend([1,2,3,4,5])
>> print mylist[1]

вывод должен быть: 1

Но когда я изменил методы __getitem__() и __setitem__(), чтобы сделать это, я получил ошибку RuntimeError: maximum recursion depth exceeded. Я много общался с этими методами, но это в основном то, что у меня было:

class MyList(list):
    def __getitem__(self, key):
        return self[key-1]
    def __setitem__(self, key, item):
        self[key-1] = item

Я думаю, проблема в том, что self[key-1] сам вызывает тот же метод, который он определяет. Если да, то каким образом я могу использовать метод list() вместо метода MyList()? Я попытался использовать super[key-1] вместо self[key-1], но это привело к жалобе TypeError: 'type' object is unsubscriptable

Любые идеи? Также, если бы вы могли указать мне на хороший учебник, это было бы здорово!

Спасибо!

4b9b3361

Ответ 1

Используйте функцию super(), чтобы вызвать метод базового класса или вызвать метод напрямую:

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

или

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

Однако это не изменит поведение других методов списка. Например, индекс остается неизменным, что может привести к неожиданным результатам:

numbers = MyList()
numbers.append("one")
numbers.append("two")

print numbers.index('one')
>>> 1

print numbers[numbers.index('one')]
>>> 'two'

Ответ 2

Вместо этого, подкласс целочисленный с использованием того же метода, чтобы определить все числа, которые будут минус один из того, что вы их установили. Вуаля.

Извините, мне пришлось. Это как шутка о Microsoft, определяющая темный стандарт.

Ответ 3

Вы можете избежать нарушения принципа замены Лискова, создав класс, который наследуется от коллекций. MutableSequence, который является абстрактным классом. Он будет выглядеть примерно так:

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)

Здесь есть одна проблема (хотя может быть и больше). Если вы указали свой новый список следующим образом:

l = MyList()
l[0]

вы на самом деле вызываете:

self._inner_list[-1]

который доставит вам последний элемент. Поэтому вы должны выполнить дополнительную проверку в методах и убедиться, что вы сохраняете обратную индексацию, если вы хотите иметь эту функцию для своего списка.

EDIT:

Вот новый код, который, я считаю, не должен иметь никаких проблем.

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)