Связанный, вложенный 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")
для завершения моей программы.
Ответы
Ответ 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