Поскольку мы не знаем заранее, нужен ли нам словарь или список, то вы не можете объединить автовивитацию со списками. Если, не откликая ответ Nosklo из связанного вопроса, вы добавляете список «функций» в базовый словарь. В основном, предполагая «сортировку» заказа для ключей и всегда используя его со списком методов. Я сделал это в качестве примера:
class AutoVivification(dict):
"""Implementation of perl's autovivification feature. Has features from both dicts and lists,
dynamically generates new subitems as needed, and allows for working (somewhat) as a basic type.
"""
def __getitem__(self, item):
if isinstance(item, slice):
d = AutoVivification()
items = sorted(self.iteritems(), reverse=True)
k,v = items.pop(0)
while 1:
if (item.start < k < item.stop):
d[k] = v
elif k > item.stop:
break
if item.step:
for x in range(item.step):
k,v = items.pop(0)
else:
k,v = items.pop(0)
return d
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
def __add__(self, other):
"""If attempting addition, use our length as the 'value'."""
return len(self) + other
def __radd__(self, other):
"""If the other type does not support addition with us, this addition method will be tried."""
return len(self) + other
def append(self, item):
"""Add the item to the dict, giving it a higher integer key than any currently in use."""
largestKey = sorted(self.keys())[-1]
if isinstance(largestKey, str):
self.__setitem__(0, item)
elif isinstance(largestKey, int):
self.__setitem__(largestKey+1, item)
def count(self, item):
"""Count the number of keys with the specified item."""
return sum([1 for x in self.items() if x == item])
def __eq__(self, other):
"""od.__eq__(y) <==> od==y. Comparison to another AV is order-sensitive
while comparison to a regular mapping is order-insensitive. """
if isinstance(other, AutoVivification):
return len(self)==len(other) and self.items() == other.items()
return dict.__eq__(self, other)
def __ne__(self, other):
"""od.__ne__(y) <==> od!=y"""
return not self == other
Это следует за основной функцией автообвинения, динамически генерирующей себя для ключей dud. Однако он также реализует некоторые из методов listed here. Это позволяет ему действовать как вещь квази-списка/dict.
Для остальных функций списка добавьте перечисленные методы. Я рассматриваю его как словарь со списком методов. Если вызывается метод списка, то он делает предположение о порядке сохраненных элементов, а именно, что строки сортируются ниже целых чисел и что ключи всегда находятся в порядке сортировки.
Он также поддерживает добавление, как пример these methods. Это происходит из моего собственного варианта использования. Мне нужно было добавлять элементы из словаря AutoVivified, но если он не существует, создается и возвращается новый объект AutoVivification
.Они не имеют целое «значение», и поэтому вы не можете сделать это:
rp = AutoVivification()
rp['a']['b'] = 3
rp['a']['b'] + rp['q']
Это поражения цели, так как я не знаю, если какая-то вещь собирается быть там, но я хочу, по умолчанию в любом случае. Поэтому я добавил методы __add__
и __radd__
. Они используют length
базового словаря как значение integer
, поэтому вновь созданный объект AV имеет значение нуля для добавления. Если у ключа есть что-то помимо AV-объекта, тогда мы получим метод добавления этой вещи, если он будет реализован.
Красивое решение. Большое спасибо. – Zhang18
Пример python, имеющий один и только один, очевидный способ сделать что-то :) – Brian
На самом деле я понял, что этот ответ работает только для 2 уровней dict и 3-го уровня списка. Есть ли способ стать агностиком? т.е. после объявления a, я могу сделать либо «a ['x»]. append (' z ') 'или' a [' x '] [' y '] [' w ']. append (' z '). '? Спасибо. – Zhang18