Подтвердить что ты не робот

Связанный, вложенный dict() получает вызовы в python

Я провожу опрос вложенного словаря, используя метод dict.get('keyword'). В настоящее время мой синтаксис...

M = cursor_object_results_of_db_query

for m in M:
    X = m.get("gparents").get("parent").get("child")
    for x in X:
        y = x.get("key")

Однако иногда один из "родительских" или "дочерних" тегов не существует, а мой script терпит неудачу. Я знаю, используя get() Я могу включить значение по умолчанию в случае, если ключ не существует формы...

get("parent", '') or
get("parent", 'orphan') 

Но если я включаю любые Null, '' или пустые, о которых я могу думать, цепочка .get("child") терпит неудачу при вызове ''.get("child"), так как "" не имеет метода .get().

Теперь я решаю это, используя кучу последовательных try-except вокруг каждого вызова .get(""), но это кажется глупым и нереализованным --- есть ли способ возврата по умолчанию "skip" или "pass" или что-то, что по-прежнему будет поддерживать цепочку и терпеть неудачу разумно, а не глубоко погружаться в ключи, которые не существуют?

В идеале, мне бы хотелось, чтобы это было понятием в виде формы:

[m.get("gparents").get("parent").get("child") for m in M]

но в настоящее время это невозможно, когда отсутствующий родитель вызывает вызов .get("child") для завершения моей программы.

4b9b3361

Ответ 1

Так как это все python dict, и вы вызываете на них метод dict.get(), вы можете использовать пустую цепочку dict для цепочки:

[m.get("gparents", {}).get("parent", {}).get("child") for m in M]

Оставив значение по умолчанию для последнего .get(), вы вернетесь к None. Теперь, если какой-либо из промежуточных ключей не найден, остальная часть цепочки будет использовать пустые словари для поиска вещей, заканчивая .get('child') возвращением None.

Ответ 2

Другой подход - признать, что если ключ не найден, dict.get возвращает None. Однако None не имеет атрибута .get, поэтому он выдает AttributeError:

for m in M:
    try:
       X = m.get("gparents").get("parent").get("child")
    except AttributeError:
       continue

    for x in X:
        y = x.get("key")
        #do something with `y` probably???

Как и Martijn, это не гарантирует, что X является итерируемым (не None). Хотя, вы можете исправить это, сделав последнее get в цепочке по умолчанию возвращением пустого списка:

 try:
    X = m.get("gparents").get("parent").get("child",[])
 except AttributeError:
    continue

Наконец, я думаю, что, вероятно, лучшим решением этой проблемы является использование reduce:

try:
    X = reduce(dict.__getitem__,["gparents","parent","child"],m)
except (KeyError,TypeError):
    pass
else:
    for x in X:
       #do something with x

Преимущество здесь в том, что вы знаете, если какой-либо из get не удалось определить тип исключенного типа. Возможно, что get возвращает неправильный тип, тогда вы получите TypeError. Однако, если словарь не имеет ключа, он вызывает KeyError. Вы можете обрабатывать их отдельно или вместе. Все, что лучше всего подходит для вашего случая использования.

Ответ 3

Как использовать небольшую вспомогательную функцию?

def getn(d, path):
    for p in path:
        if p not in d:
            return None
        d = d[p]
    return d

а затем

[getn(m, ["gparents", "parent", "child"]) for m in M]

Ответ 4

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

def get_nested(dict_, *keys, default=None):
    if not isinstance(dict_, dict):
        return default
    elem = dict_.get(keys[0], default)
    if len(keys) == 1:
        return elem
    return get_nested(elem, *keys[1:], default=default)

Например:

In [29]: a = {'b': {'c': 1}}
In [30]: get_nested(a, 'b', 'c')
Out[30]: 1
In [31]: get_nested(a, 'b', 'd') is None
Out[31]: True