Я создаю вложенный словарь в python, содержащий записи для файлов, хранящихся в ведро Amazon S3. Так что если в моем ведре у меня есть несколько файлов, как это:Лучшая практика для рекурсивного обновления вложенного словаря?
mys3bucket/подкаталог/world.txt
mys3bucket/подкаталог/hello.txt
mys3bucket/foobar.txt
I хотите сделать словарь в питоне в этом формате:
dict = { 'subdir' : { 'world.txt' : 'file', 'hello.txt' : 'file' }, 'foobar.txt' :'file' }
значение («файл») не имеет никакого значения в этом контексте, но они могут быть заменены с размером файла или с omething else (для этого вопроса это не имеет значения). Дело в том, что словарь должен быть вложен из-за подкаталогов, и, очевидно, уровень вложенности зависит от того, насколько глубоким является конкретное дерево. Я написал рабочую реализацию, которая уже делает это:
#!/usr/bin/python
import httplib
from re import compile as recomp
pattern = recomp("<Key>(.*?)<\/Key>")
def main(bucketname='elasticmapreduce'):
url = bucketname + '.s3.amazonaws.com'
HTTPconnection = httplib.HTTPConnection(url)
HTTPconnection.request("GET", "/")
response = HTTPconnection.getresponse()
content = response.read()
fileslist = pattern.findall(content)
filesdict = {}
def intoDict(path,mydict):
if len(path) == 1:
mydict[path[0]] = 'file'
return mydict
else:
name = path.pop(0)
if name in mydict:
mydict[name] = intoDict(path,mydict[name])
else:
mydict[name] = intoDict(path,{})
return mydict
for line in fileslist:
splitline = line.split('/')
if splitline[-1] != '':
filesdict = intoDict(splitline,filesdict)
return filesdict
имя ведра по умолчанию просто установить в общественном ведро, которое я нашел, чтобы быть в состоянии проверить код на.
Причина для регулярного выражения заключается в том, что S3 возвращает текст, отформатированный в формате XML, когда вы запрашиваете ведро, поэтому регулярное выражение просто извлекает из него пути к файлам.
Меня интересует эффективность моей реализации. Как вы можете видеть в цикле for, я передаю весь словарь каждый раз функции intoDict()
и переписываю его, когда он возвращается. Функция intoDict()
является рекурсивной/саморегуляционной, что и происходит в гнездовании. Трудно объяснить, что происходит, но я думаю, что вы можете это понять. Мне потребовалось некоторое время, чтобы прийти к этому решению, потому что сначала я пытался использовать dictionary.update()
для обновления словаря внутри цикла for
, но он работал неправильно.
Мне было интересно, может ли кто-нибудь, кто имеет опыт в вложенных словарях и/или рекурсивных функциях, прокомментировать, является ли это правильным способом достижения того, что я пытаюсь, или можно ли это сделать лучше.
Спасибо @niemmi, это действительно круто! Вы представили мне пару новых концепций. Я изменил код для работы без 'defaultdict', поэтому я добавил: ' if path [i] не в d: d [путь [i]] = {} ' Что-то я не понимаю: когда мы делаем assign 'd = filesdict' Я предполагаю, что Python создает какую-то динамическую связь между двумя словарями? Извиняюсь, если это глупый вопрос. –
@KirillVourlakidis Не глупый вопрос.Я не уверен, что вы подразумеваете под динамической ассоциацией, но это всего лишь две ссылки на один и тот же объект. Теперь после выполнения строки 'd = d [путь [i]]' '' d' относится к дочернему 'dict'. Когда следующий путь обрабатывается, нам нужно начинать с root снова, поэтому нам нужно сохранить ссылку там ('filesdict'). – niemmi
Это имеет смысл в отношении ссылки на один и тот же объект! В моей голове я представляю себе, что Python создает копию всего словаря и связывает их вместе, в результате чего, если кто-то изменен, он автоматически меняет другой, таким образом, мой комментарий «динамической ассоциации». Как вы можете видеть, я все еще неравнодушен к тому, чтобы обойти всю объектно-ориентированную вещь. –