Как наследовать и расширять список объектов в Python? - PullRequest
43 голосов
/ 04 ноября 2010

Я заинтересован в использовании объекта списка 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

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

Спасибо!

Ответы [ 4 ]

51 голосов
/ 04 ноября 2010

Используйте функцию 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'
26 голосов
/ 04 ноября 2010

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

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

16 голосов
/ 25 мая 2016

Вы можете избежать нарушения принципа подстановки Лискова, создав класс, который наследуется от collection.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]

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

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 голосов
/ 16 марта 2018
class ListExt(list):
    def extendX(self, l):
        if l:
            self.extend(l)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...