Есть ли простой способ переопределить метод объекта списка __getitem__?

73
8

Я пытаюсь определить объект списка объектов по умолчанию:

class ilist(list):
def __init__(self,r=list(),dft=None):
list.__init__(self,r)
self.dft=dft
def __getitem__(self,n):
if len(self)<=n:
for i in range(n-len(self)+1):
self.append(self.dft)
for i,v in enumerate(self):
if i+1==len(self):
return v

x=ilist()
print x[4]
print x

Оно работает.

>>> 
None
[None, None, None, None, None]

Но я думаю, что ужасно спросить моего подвига. Я пробовал следующий метод:

def __getitem__(self,n):
from operator import getitem
if len(self)<=n:
for i in range(n-len(self)+1):
self.append(self.dft)
return getitem(self,n)

но факт показывает, что он полностью равен self [n] и вызывает RuntimeError: maximum recursion depth exceeded

Я также попытался заимствовать метод list родительских классов. Но форма x.__getitem__(y). Я не знаю, как приспособить его к ilist.

Итак, наконец, мое ужасное решение выходит. Сырая и грубая сила. Есть ли эффективное или простое решение? Заранее спасибо.

спросил(а) 2021-01-12T13:55:28+03:00 1 неделя, 4 дня назад
1
Решение
105

Используйте super() для доступа к оригиналу __getitem__:

def __getitem__(self,n):
while len(self) <= n:
self.append(self.dft)
return super(ilist, self).__getitem__(n)

Демо-версия:

>>> class ilist(list):
... def __init__(self,r=list(),dft=None):
... list.__init__(self,r)
... self.dft=dft
... def __getitem__(self, n):
... while len(self) <= n:
... self.append(self.dft)
... return super(ilist, self).__getitem__(n)
...
>>> il = ilist()
>>> il[3]
>>> il
[None, None, None, None]
>>> il[2] = 5
>>> il
[None, None, 5, None]
>>> il[2]
5

Возможно, вы захотите также поддержать нарезку:

def __getitem__(self, n):
maxindex = n
if isinstance(maxindex, slice):
maxindex = maxindex.indices(len(self))[1]
while len(self) <= maxindex:
self.append(self.dft)
return super(ilist, self).__getitem__(n)

и если вы хотите поддерживать присвоение произвольным индексам, добавьте метод __setitem__:

def __setitem__(self, n, val):
maxindex = n
if isinstance(maxindex, slice):
maxindex = maxindex.indices(len(self))[1]
while len(self) <= maxindex:
self.append(self.dft)
return super(ilist, self).__setitem__(n, val)

но затем вы можете переместить создание значения по умолчанию в вспомогательный метод:

class ilist(list):
def __init__(self, r=None, dft=None):
if r is None:
r = []
list.__init__(self, r)
self.dft=dft

def _ensure_length(n):
maxindex = n
if isinstance(maxindex, slice):
maxindex = maxindex.indices(len(self))[1]
while len(self) <= maxindex:
self.append(self.dft)

def __getitem__(self, n):
self._ensure_length(n)
return super(ilist, self).__getitem__(n)

def __setitem__(self, n, val):
self._ensure_length(n)
return super(ilist, self).__getitem__(n)

ответил(а) 2021-01-12T13:55:28+03:00 1 неделя, 4 дня назад
61

После добавления необходимого количества элементов вы можете просто вызвать оригинальный (переопределенный) метод __getitem__ следующим образом.

class ilist(list):
def __init__(self,r=list(),dft=None):
list.__init__(self,r)
self.dft=dft
def __getitem__(self,n):
if len(self)<=n:
for i in range(n-len(self)+1):
self.append(self.dft)
return super(ilist, self).__getitem__(n)

x=ilist()
print x[4]
print x

ответил(а) 2021-01-12T13:55:28+03:00 1 неделя, 4 дня назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема