2016-02-26 3 views
2

Есть ли простой и сжатый способ получить значение из вложенного dict и получить None, если его там нет?Python получает вложенный элемент dict

d1 = None 
d2 = {} 
d3 = {"a": {}} 
d4 = {"a": {"b": 12345}} 
ds = [d1, d2, d3, d4] 


def nested_get(d): 
    # Is there a simpler concise one-line way to do exactly this, query a nested dict value, and return None if 
    # it doesn't exist? 
    a_val = d.get("a") if d else None 
    b_val = a_val.get("b") if a_val else None 
    return b_val 

if __name__ == "__main__": 
    bs = [nested_get(d) for d in ds] 
    print("bs={}".format(bs)) 
+0

Ваше решение работает только для вложенных словарей 2 уровня. Также какое значение вы хотите вернуть, когда одни и те же ключи найдены на разных уровнях? – Maroun

+0

Вы можете объединить два метода get get. Например, просто верните 'return d.get (" a "). Get ('b'), если d else None' из вашей функции. Это то, что вы ищете? – gtlambert

ответ

1

Это должно работать:

def nested_get(d, *keys): 
    for key in keys: 
     if d is None: 
      break 
     d = d.get(key) 
    return d 
+0

Спасибо! Я просто написал и разместил почти то же самое. – clay

1

OK, используя простую пользовательскую функцию, я могу сделать это, как общее лаконичным решение:

d1 = None 
d2 = {} 
d3 = {"a": {}} 
d4 = {"a": {"b": 12345}} 
ds = [d1, d2, d3, d4] 


def get_nested_dict_value(d, *args): 
    for a in args: 
     d = d.get(a) if d else None 
    return d 


if __name__ == "__main__": 
    bs = [get_nested_dict_value(d, "a", "b") for d in ds] 
    print("bs={}".format(bs)) 
1

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

class QueryDict(dict): 
    def __getitem__(self, keys): 
     current = self 
     try: 
      for key in keys: 
       current = dict.__getitem__(current, key) 
      return current 
     except (TypeError, KeyError): 
      return None 


d = {"a": {"b": {"c": 12345}}} 
d = QueryDict(d) 
print d['a','b','c'] # 12345 
print d['a,c,e'] # None 

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

class QueryDict(dict): 
    def __getitem__(self, key_string): 
     current = self 
     try: 
      for key in key_string.split(','): 
       current = dict.__getitem__(current, key) 
      return current 
     except (TypeError, KeyError): 
      return None 


d = {"a": {"b": {"c": 12345}}} 
d = QueryDict(d) 
print d['a,b,c'] # 12345. 
print d['a,c,e'] # None 
0

Если вы не хотите указать свой «путь» в гнездовой Словаре как путь строки (например, каталог), а не набор отдельных клавиш, это работало для наших нужд:

def deep_get(d, path, default=None): 
    """Get a deeply nested value in a dict based on multiple keys 

    :param d: The dictionary 
    :param path: The key path to search separated by '/' 
    :param default: The default value to return if there is nothing 
    :returns: The value at the given path or the default 
    """ 
    dd = d 
    split = path.split("/") 
    for i, key in enumerate(split): 
     try: 
      dd = dd.get(key, {}) 
     except AttributeError as exc: 
      p = "/".join(split[0:i]) 
      raise AttributeError("{} at {}".format(exc.message, p)), \ 
       None, sys.exc_info()[2] 
    return dd or default 

где использование так просто, как

d = { 
    'a': { 
    'b': { 
     'c': { 
     'd': "hi!" 
     } 
    } 
    } 
} 

print deep_get(d, 'a/b/c/d') 
Смежные вопросы