Какой лучший способ инициализировать диктовку в Python?
Много раз в Perl я буду делать что-то вроде этого:
$myhash{foo}{bar}{baz} = 1
Как бы я перевести это на Python? Пока что у меня есть:
if not 'foo' in myhash:
myhash['foo'] = {}
if not 'bar' in myhash['foo']:
myhash['foo']['bar'] = {}
myhash['foo']['bar']['baz'] = 1
Есть ли способ лучше?
5 ответов
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
Тестирование:
a = AutoVivification()
a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6
print a
Выход:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
Если нужное вам количество вложений фиксировано, collections.defaultdict
это чудесно.
например, вложение двух глубоких:
myhash = collections.defaultdict(dict)
myhash[1][2] = 3
myhash[1][3] = 13
myhash[2][4] = 9
Если вы хотите перейти на другой уровень вложенности, вам нужно сделать что-то вроде:
myhash = collections.defaultdict(lambda : collections.defaultdict(dict))
myhash[1][2][3] = 4
myhash[1][3][3] = 5
myhash[1][2]['test'] = 6
edit: MizardX указывает, что мы можем получить полную универсальность с помощью простой функции:
import collections
def makehash():
return collections.defaultdict(makehash)
Теперь мы можем сделать:
myhash = makehash()
myhash[1][2] = 4
myhash[1][3] = 8
myhash[2][5][8] = 17
# etc
Есть ли причина, по которой это должно быть диктовкой? Если для этой конкретной структуры нет веских причин, вы можете просто проиндексировать слова с помощью кортежа:
mydict = {('foo', 'bar', 'baz'):1} # Initializes dict with a key/value pair
mydict[('foo', 'bar', 'baz')] # Returns 1
mydict[('foo', 'unbar')] = 2 # Sets a value for a new key
Скобки требуются, если вы инициализируете dict с помощью ключа кортежа, но вы можете опустить их при установке / получении значений с помощью []:
mydict = {} # Initialized the dict
mydict['foo', 'bar', 'baz'] = 1 # Sets a value
mydict['foo', 'bar', 'baz'] # Returns 1
Я думаю, что буквальный перевод будет:
mydict = {'foo' : { 'bar' : { 'baz':1}}}
Вызов:
>>> mydict['foo']['bar']['baz']
дает вам 1.
Это выглядит немного грубым для меня, хотя.
(Я не Perl парень, хотя, так что я думаю, что делает ваш Perl)
Такие вложенные словари (часто) называются объектами бедняков. Да, есть смысл, и он может соотноситься с объектно-ориентированной природой питонов.