Создание списка по умолчанию в python
Я пытаюсь создать эквивалент списка для очень полезного collections.defaultdict
. Следующий дизайн прекрасно работает:
class defaultlist(list):
def __init__(self, fx):
self._fx = fx
def __setitem__(self, index, value):
while len(self) <= index:
self.append(self._fx())
list.__setitem__(self, index, value)
Вот как вы его используете:
>>> dl = defaultlist(lambda:'A')
>>> dl[2]='B'
>>> dl[4]='C'
>>> dl
['A', 'A', 'B', 'A', 'C']
Что следует добавить в список по умолчанию, чтобы поддерживать следующее поведение?
>>> dl = defaultlist(dict)
>>> dl[2]['a'] = 1
>>> dl
[{}, {}, {'a':1}]
Ответы
Ответ 1
В примере, который вы даете, сначала попробуйте извлечь несуществующее значение в списке, как вы это делаете dl[2]['a']
, Python сначала извлекает третий элемент (индекс 2) в списке, а затем переходит к элементу названный 'a' на этом объекте, поэтому вы должны реализовать свое автоматическое расширение поведения к методу __getitem__
, например:
class defaultlist(list):
def __init__(self, fx):
self._fx = fx
def _fill(self, index):
while len(self) <= index:
self.append(self._fx())
def __setitem__(self, index, value):
self._fill(index)
list.__setitem__(self, index, value)
def __getitem__(self, index):
self._fill(index)
return list.__getitem__(self, index)
Ответ 2
Доступен пакет python:
$ pip install defaultlist
Добавленные индексы по умолчанию заполняются None.
>>> from defaultlist import defaultlist
>>> l = defaultlist()
>>> l
[]
>>> l[2] = "C"
>>> l
[None, None, 'C']
>>> l[4]
>>> l
[None, None, 'C', None, None]
Срезы и отрицательные знаки поддерживаются аналогично
>>> l[1:4]
[None, 'C', None]
>>> l[-3]
'C'
Простые factory функции могут быть созданы с помощью лямбда.
>>> l = defaultlist(lambda: 'empty')
>>> l[2] = "C"
>>> l[4]
'empty'
>>> l
['empty', 'empty', 'C', 'empty', 'empty']
Также возможно реализовать расширенные функции factory:
>>> def inc():
... inc.counter += 1
... return inc.counter
>>> inc.counter = -1
>>> l = defaultlist(inc)
>>> l[2] = "C"
>>> l
[0, 1, 'C']
>>> l[4]
4
>>> l
[0, 1, 'C', 3, 4]
Подробнее см. Документация.