Проверка словаря с использованием точечной нотации

Этот дует мой разум. Учитывая следующий словарь:

    d = {"a":{"b":{"c":"winning!"}}}

У меня есть эта строка (из внешнего источника, и я не могу изменить эту метафору).

    k = "a.b.c"

Мне нужно определить, есть ли у словаря ключ 'c', поэтому я могу добавить его, если это не так.

Это работает плавно для получения значения точечной нотации:

    reduce(dict.get, key.split("."), d)

но я не могу понять, как "уменьшить" проверку has_key или что-то в этом роде.

Моя конечная проблема заключается в следующем: учитывая "a.b.c.d.e", мне нужно создать все элементы, необходимые в словаре, но не топать их, если они уже существуют. Если кто-то знает способ свиста, чтобы сделать все это, вы станете моим героем.

Ответ 1

... или используя рекурсию:

def put(d, keys, item):
    if "." in keys:
        key, rest = keys.split(".", 1)
        if key not in d:
            d[key] = {}
        put(d[key], rest, item)
    else:
        d[keys] = item

def get(d, keys):
    if "." in keys:
        key, rest = keys.split(".", 1)
        return get(d[key], rest)
    else:
        return d[keys]

Ответ 2

Вы можете использовать бесконечный, вложенный defaultdict:

>>> from collections import defaultdict
>>> infinitedict = lambda: defaultdict(infinitedict)
>>> d = infinitedict()
>>> d['key1']['key2']['key3']['key4']['key5'] = 'test'
>>> d['key1']['key2']['key3']['key4']['key5']
'test'

Учитывая вашу пунктирную строку, вот что вы можете сделать:

>>> import operator
>>> keys = "a.b.c".split(".")
>>> lastplace = reduce(operator.getitem, keys[:-1], d)
>>> lastplace.has_key(keys[-1])
False

Вы можете установить значение:

>>> lastplace[keys[-1]] = "something"
>>> reduce(operator.getitem, keys, d)
'something'
>>> d['a']['b']['c']
'something'

Ответ 3

Как насчет итеративного подхода?

def create_keys(d, keys):
    for k in keys.split("."):
        if not k in d: d[k] = {}  #if the key isn't there yet add it to d
        d = d[k]                  #go one level down and repeat

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

def create_keys(d, keys, value):
    keys = keys.split(".")
    for k in keys[:-1]:
        if not k in d: d[k] = {}
        d = d[k]            
    d[keys[-1]] = value

Ответ 4

d = {"a":{}}
k = "a.b.c".split(".")

def f(d, i):
    if i >= len(k):
        return "winning!"
    c = k[i]
    d[c] = f(d.get(c, {}), i + 1)
    return d

print f(d, 0)
"{'a': {'b': {'c': 'winning!'}}}"