2014-11-17 2 views
6

Многих SO сообщений показать вам, как эффективно проверять наличие ключа в словаре, например, Check if a given key already exists in a dictionaryпроверки питона многоуровневого ДИКТ ключ существование

Как это сделать для ключа мульти уровня? Например, если d["a"]["b"] является ДИКТ, как я могу проверить, если d["a"]["b"]["c"]["d"] существует не делать что-то чудовищное, как это:

if "a" in d and isInstance(d["a"], dict) and "b" in d["a"] and isInstance(d["a"]["b"], dict) and ... 

Есть некоторые синтаксис как

if "a"/"b"/"c"/"d" in d 

То, что я на самом деле использовать это для: мы имеем jsons, разбираемся в dicts, используя simplejson, что мне нужно извлечь значения из. Некоторые из этих значений вложены в три и четыре уровня в глубину; но иногда значение вообще не существует. Так что я хотел что-то вроде:

val = None if not d["a"]["b"]["c"]["d"] else d["a"]["b"]["c"]["d"] #here d["a"]["b"] may not even exist 

EDIT: предпочитают не вылетать, если некоторые подключ существует, но это не словарь, например, d["a"]["b"] = 5.

+0

Это не базовая функция языка, поскольку нет никакого способа, чтобы добавить новый синтаксис. Вы можете определить новый класс, который переопределяет функцию __contains__, которая вызывается выражением «x in y». Вы хотите эффективность синтаксиса или исполнения? Возможно, это не одно и то же. – mobiusklein

+0

Ну, моя цель была эффективным синтаксисом, но это было в предположении, что время поиска словаря O (1) будет сохранено. Однако я понимаю, что сбор исключений стоит дорого, поэтому, возможно, это более активно, чем просто проверка существования ключа. – Tommy

+0

Обработка исключений не будет дорогостоящей. То, что вы хотите принципиально, не на том языке, о котором указывал utdemir. Ответ Мейтэма близок к тому, что вы хотите, не делая гораздо больше работы, определяя класс, как я уже упоминал ранее, а затем испытываю трудности с тем, чтобы сделать 'simplejson' распаковывать объекты в эти слова, а не ванильные словари. – mobiusklein

ответ

1

UPDATE: я в конечном итоге писать свой собственный открытый источник, pippable библиотека, которая позволяет один сделать это: https://pypi.python.org/pypi/dictsearch

7

К сожалению, нет встроенного синтаксиса или общей библиотеки для запросов к таким словарям.

Однако, я считаю, самый простой (и я думаю, что это достаточно эффективно), что вы можете сделать, это:

d.get("a", {}).get("b", {}).get("c") 

Edit: Это не очень часто, но есть: https://github.com/akesterson/dpath-python

Edit 2: Примеры:

>>> d = {"a": {"b": {}}} 
>>> d.get("a", {}).get("b", {}).get("c") 
>>> d = {"a": {}} 
>>> d.get("a", {}).get("b", {}).get("c") 
>>> d = {"a": {"b": {"c": 4}}} 
>>> d.get("a", {}).get("b", {}).get("c") 
4 
+0

d.get? И возвращает ли это логическое значение или элемент? – Tommy

+0

Из 'help ({}. Get)': 'D.get (k [, d]) -> D [k], если k в D, иначе d. d по умолчанию - None. Он возвращает элемент, если он найден, 'Нет', если это не так. – utdemir

+0

Право, опечатка, отредактировано. – utdemir

1

Это, вероятно, не очень хорошая идея, и я бы не рекомендовал использовать это в прод. Однако, если вы просто делаете это для учебных целей, то ниже может работать для вас.

def rget(dct, keys, default=None): 
    """ 
    >>> rget({'a': 1}, ['a']) 
    1 
    >>> rget({'a': {'b': 2}}, ['a', 'b']) 
    2 
    """ 
    key = keys.pop(0) 
    try: 
     elem = dct[key] 
    except KeyError: 
     return default 
    except TypeError: 
     # you gotta handle non dict types here 
     # beware of sequences when your keys are integers 
    if not keys: 
     return elem 
    return rget(elem, keys, default)