2012-04-29 3 views
4

новенького питона, Скажем, у меня есть Dict:Сохранение словаря пути в Python

kidshair = {'allkids':{'child1':{'hair':'blonde'}, 
         'child2':{'hair':'black'}, 
         'child3':{'hair':'red'}, 
         'child4':{'hair':'brown'}}} 

Если child3 регулярно меняет свой цвет волоса, я мог бы написать заявление, чтобы ускорить обработку данных. В этом примере я хотел бы использовать:

kidshair['allkids']['child3']['hair'] = ... 

Есть ли способ, чтобы сохранить этот путь как переменные, так что я могу получить доступ к нему в моем досуговоге? Очевидно,

mypath = kidshair['allkids']['child3']['hair'] 

Результаты mypath = 'red'. Есть ли возможный способ жесткого кода сам путь, так что я мог бы использовать:

mypath = 'blue' 

в reperesent

kidshair['allkids']['child3']['hair'] = 'blue' 

Kind спасибо, ATfPT

+1

Проверьте форматирование. 'kidshair' будет генерировать синтаксическую ошибку, как сейчас. –

+1

Связано это: http://stackoverflow.com/questions/3797957/python-easily-access-deeply-nested-dict-get-and-set (хотя не совсем то, что вы просите) –

+0

@JoelCornett Спасибо, отредактировал , –

ответ

7

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

kidshair['allkids', 'child3', 'hair'] 
mypath = ('allkids', 'child3', 'hair') 
kidshair[mypath] 

Единственный проблема заключается в том, что вы не можете получить часть словаря, поэтому, например, вы не можете (легко/эффективно) получить доступ ко всему, что нужно сделать с 'child3'. Это может быть или не быть подходящим решением для вас в зависимости от вашего использования.

Альтернативного с текущей структурой является, чтобы сделать что-то вроде этого:

>>> from functools import partial 
>>> test = {"a": {"b": {"c": 1}}} 
>>> def itemsetter(item): 
...  def f(name, value): 
...   item[name] = value 
...  return f 
... 
>>> mypath = partial(itemsetter(test["a"]["b"]), "c") 
>>> mypath(2) 
>>> test 
{'a': {'b': {'c': 2}}} 

Здесь мы делаем функцию itemsetter(), которая (в духе operator.itemgetter()) дает нам функцию, которая устанавливает соответствующий ключ данный словарь. Затем мы используем functools.partial для генерации версии этой функции с помощью ключа, который мы хотим предварительно заполнить. Это не совсем mypath = blue, но это неплохо.

Если вы не хотите возиться с делать что-то последовательное к operator модулю, вы можете просто сделать:

def dictsetter(item, name): 
    def f(value): 
     item[name] = value 
    return f 

mypath = dictsetter(test["a"]["b"], "c") 

mypath(2) 
+1

Блестяще описал, позволил мне больше, чем решить мою проблему. Искреннее спасибо. –

0

Ближайшими вы можете сделать с вашей текущей структурой данных, чтобы получить последний Dict и использовать его непосредственно:

child = kidshair['allkids']['child3'] 

child['hair'] = 'blue' 

Это происходит потому, что в Python, назначение стиля

name = value 

просто связывает новый объект с «переменной» name. Невозможно перегрузить это, и привязка не может повлиять на какой-либо другой объект (кроме освобождения объекта, привязанного к этому имени, до сих пор).

С другой стороны, это:

name[key] = value 

совершенно иной, поскольку он выполняет действие (устанавливает элемент) на объекте в настоящее время в name (Dict в вашем случае).

1

Вы можете сохранить ссылку на kidshair['allkids']['child3'] легко:

thiskid = kidshair['allkids']['child3'] 
thiskid['hair'] = 'blue' 

Вы не можете сохранить весь путь, поскольку присваивание изменяет hair ключ в kidshair['allkids']['child3'] словаре.
Если вы хотите изменить словарь, вы должны иметь ссылку на него, а не на то, что он содержит.

5

Вы можете создать набор функций, который обращается к 'путь' для данного словаря:

def pathGet(dictionary, path): 
    for item in path.split("/"): 
     dictionary = dictionary[item] 
    return dictionary 

def pathSet(dictionary, path, setItem): 
    path = path.split("/") 
    key = path[-1] 
    dictionary = pathGet(dictionary, "/".join(path[:-1])) 
    dictionary[key] = setItem 

Использование:

>>> pathGet(kidshair, "allkids/child1/hair") 
'blonde' 
>>> pathSet(kidshair, "allkids/child1/hair", "blue") 
>>> kidshair['allkids']['child1'] 
{'hair': 'blue'} 
+0

В ретроспективе, вероятно, проще передать кортежи в «путь» вместо объединения и разделения строк. –

+0

Я решил создать аналогичный код, прежде чем найти этот вопрос. Однако, поскольку вы предположили, что я создал функции, которые принимали кортежи, наряду с двумя вспомогательными функциями, которые принимали строки и называли функции пути с вызовом split() в качестве аргумента кортежа. – Matt

Смежные вопросы