Я опрашиваю вложенный словарь, используя метод 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")

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

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

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

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

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

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

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

24
Mittenchops 23 Янв 2013 в 20:24

4 ответа

Лучший ответ

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

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

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

69
Martijn Pieters 23 Янв 2013 в 16:32

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

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
georg 23 Янв 2013 в 16:41

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

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
4
Никита Конин 17 Окт 2017 в 12:25

Другой подход заключается в том, чтобы признать, что если ключ не найден, 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???

Как и ответ Мартина, это не гарантирует, что 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. Вы можете справиться с этим по отдельности или вместе. Все, что работает лучше всего для вашего случая использования.

8
mgilson 23 Янв 2013 в 16:52