Есть более четкий способ проверить, если ключ похоронен в дикт существует без проверки каждого уровня самостоятельно?
Допустим, мне нужно получить это значение в выкапывании (пример взят из Викиданных):
x = s['mainsnak']['datavalue']['value']['numeric-id']
Чтобы убедиться, что это не конец с ошибки во время выполнения нужно проверить каждого уровня следующим образом:
if 'mainsnak' in s and 'datavalue' in s['mainsnak'] and 'value' in s['mainsnak']['datavalue'] and 'nurmeric-id' in s['mainsnak']['datavalue']['value']:
x = s['mainsnak']['datavalue']['value']['numeric-id']
Другим способом я могу думать, чтобы решить это обернуть это в поймай
конструкт, который я чувствую, что тоже довольно неудобно для такой простой задачи.
Я ищу что-то вроде:
x = exists(s['mainsnak']['datavalue']['value']['numeric-id'])
которая возвращает true
, если всех уровнях существует.
Чтобы быть кратким, в Python вы должны доверять это легче просить прощения, чем разрешения
try:
x = s['mainsnak']['datavalue']['value']['numeric-id']
except KeyError:
pass
Вот как я имею дело с вложенными ключами дикт:
def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
if not isinstance(element, dict):
raise AttributeError('keys_exists() expects dict as first argument.')
if len(keys) == 0:
raise AttributeError('keys_exists() expects at least two arguments, one given.')
_element = element
for key in keys:
try:
_element = _element[key]
except KeyError:
return False
return True
Пример:
data = {
"spam": {
"egg": {
"bacon": "Well..",
"sausages": "Spam egg sausages and spam",
"spam": "does not have much spam in it"
}
}
}
print 'spam (exists): {}'.format(keys_exists(data, "spam"))
print 'spam > bacon (do not exists): {}'.format(keys_exists(data, "spam", "bacon"))
print 'spam > egg (exists): {}'.format(keys_exists(data, "spam", "egg"))
print 'spam > egg > bacon (exists): {}'.format(keys_exists(data, "spam", "egg", "bacon"))
Выход:
spam (exists): True
spam > bacon (do not exists): False
spam > egg (exists): True
spam > egg > bacon (exists): True
Это петля в данный "элемент" тестирование каждого ключа в заданном порядке.
Я предпочитаю это к переменной.вам('ключ', {})` методов я нашел, потому что следующим EAFP.
Функции, за исключением можно назвать так: keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)
. По крайней мере, два аргумента являются обязательными, элемент и один ключ, но вы можете добавить сколько ключей вы хотите.
Если вам нужно использовать вид карты, вы можете сделать что-то вроде:
expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)
Вы могли бы использовать `.уберите со значениями по умолчанию:
s.get('mainsnak', {}).get('datavalue', {}).get('value', {}).get('numeric-id')
но это почти наверняка менее ясно, чем с помощью try и except.
Попробовать/за исключением, кажется, чтобы быть наиболее подходящие для Python способ сделать это. Следующая рекурсивная функция должна работать (возвращает none, если один из ключей не был найден в dict):
def exists(obj, chain):
_key = chain.pop(0)
if _key in obj:
return exists(obj[_key], chain) if chain else obj[_key]
myDict ={
'mainsnak': {
'datavalue': {
'value': {
'numeric-id': 1
}
}
}
}
result = exists(myDict, ['mainsnak', 'datavalue', 'value', 'numeric-id'])
print(result)
>>> 1
Я предлагаю вам использовать питон-Бенедикт
, твердого питона дикт подкласс с полной поддержкой путь и много вспомогательных методов.
Вам просто нужно отдать ваш существующий дикт:
s = benedict(s)
Теперь ваш дикт имеет полную поддержку путь и вы можете проверить, если ключ существует в подходящие для Python способ, с помощью оператора in:
if 'mainsnak.datavalue.value.numeric-id' in s:
# do stuff
Здесь репозитория библиотеки и документация: https://github.com/fabiocaccamo/python-benedict
Вы можете использовать pydash
, чтобы проверить, если существует: http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Или вам значение (вы даже можете установить по умолчанию для возвращения, если не'т существуют): http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Вот пример:
>>> get({'a': {'b': {'c': [1, 2, 3, 4]}}}, 'a.b.c[1]')
2
Блок try/за исключением способ является наиболее чистым, без конкурса. Однако, это также считается исключение в моей IDE, что выполнение привалы во время отладки.
Кроме того, мне не нравится использование исключений как способ утверждения контроля, который является по существу то, что происходит с try/поймать.
Вот короткое решение, которое не использовать рекурсию, и поддерживает значение по умолчанию:
def chained_dict_lookup(lookup_dict, keys, default=None):
_current_level = lookup_dict
for key in keys:
if key in _current_level:
_current_level = _current_level[key]
else:
return default
return _current_level
У меня была такая же проблема и последние питона Либ выскочил: https://pypi.org/project/dictor/ https://github.com/perfecto25/dictor
Так что в вашем случае: `` от режиссера импорт дикторский
х = дикторский(с 'mainsnak.datavalue.значение.числовой-ID и#39;) ``
Примечание: Я не'т, как 'режиссера' название, поскольку она еще'т понять, что это на самом деле. Поэтому я'м, используя его как:
от режиссера импорт дикторский как экстракт х = выдержка(с 'mainsnak.datavalue.значение.числовой-ID и#39;)
Не мог'т придумать лучшего наименования, чем "тяжелых". Не стесняйтесь комментировать, если вы придумали более жизнеспособным именования. safe_get
, robust_get
не'т чувствовал себя хорошо в моем случае.
Я написала библиотеки синтаксического анализа данных dataknead
для таких случаев, в основном потому, что я был расстроен в формате JSON Викиданных API возвращает так же.
С этой библиотекой вы могли бы сделать нечто подобное
from dataknead import Knead
numid = Knead(s).query("mainsnak/datavalue/value/numeric-id").data()
if numid:
# Do something with `numeric-id`