Наличие в словаре ключ : значение
Устал уже изобретать велосипед и работать со словарями вручную. Кто подскажет универсальный способ проверять наличие ключа : значения в словаре. Важно! Вложенность словаря достигает 5 уровней.
Могут быть следующие ситуации:
- Ключ : значение существуют
- Ключ : значение НЕ существуют
- Ключ существует : значение пустое или None
Возвращать True только в первом случае, не выкидывать исключения.
На данный момент я проверяю обычными методами словаря, например так:
if owner.get("email"): # Может быть или не быть
if owner.get('email').get("value"): # Может быть или не быть, также значение может быть None
out["emailAddress"] = owner["email"]["value"]
out["invoiceDeliveryType"] = 1
else:
out["invoiceDeliveryType"] = 2
else:
out["invoiceDeliveryType"] = 2
Есть ли универсальный способ для определения, что ключ : значение существует и значение не пусто, не зависимо от уровня вложенности
Входные данные:
1 случай:
{
"data":{
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":{
"value":"[email protected]",
"note" : "notice"
},
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
2 случай
{
"data":{
"invoice_id": 17304,
"location_name": "live"
}
}
3 случай
{
"data":{
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":None,
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
Ответы (3 шт):
Можно через сторонний модуль dpath (pip install dpath) делать запрос по путям (для вашей задачи сделайте, например, функцию на основе этого модуля, что и путь проверит и значение):
import dpath.util
data = {
"data": {
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":{
"value":"[email protected]",
"note" : "notice"
},
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
print(dpath.util.get(data, 'data/owner/email/value'))
# [email protected]
Если в пути что-то будет отсутствовать, то будет выброшено KeyError, что случится для второго и третьего вариантов. Мы можем ловить KeyError, а для удобства сделаем функцию:
def has_key(data: dict, path: str) -> bool:
try:
dpath.util.get(data, path)
return True
except KeyError:
return False
Проверяем:
data1 = {
"data": {
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":{
"value":"[email protected]",
"note" : "notice"
},
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
data2 = {
"data":{
"invoice_id": 17304,
"location_name": "live"
}
}
data3 = {
"data":{
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":None,
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
print(has_key(data1, 'data/owner/email/value')) # True
print(has_key(data2, 'data/owner/email/value')) # False
print(has_key(data3, 'data/owner/email/value')) # False
Ну можно немного сократить ваш код, плюс я написал функцию, достающую значение из вложенного словаря, хотя, кажется, уже были подобные вопросы и там должны быть подобные функции реализованы:
def safe_get(data, key_chain):
for key in key_chain.split('/'):
if not (data and key in data):
return None
data = data[key]
return data
email = safe_get(data_dict, 'data/owner/email/value')
if email:
out["emailAddress"] = email
out["invoiceDeliveryType"] = 1
else:
out["invoiceDeliveryType"] = 2
Можно сделать без библиотек через ванильную рекурсию внутри словаря.
Итерируем словарь, если нашли ключ-значение, то их возвращаем в виде [1, (ключ, значение)]. Если находим словарь, то уходим глубже. Если ничего не нашли, то возвращаем [2, None].
Я немного добавил код. Если находит ключ email, а внутри у него не словарь, а строка, то также выводится [1, (ключ, значение)].
def chekc_pair(data: dict, key: str, key_value: str):
for k, v in data.items():
if k == key:
return [1, (k, v.get(key_value))] if (isinstance(v, dict) and v.get(key_value)) \
else [1, (k, v)] if isinstance(v, str) else [2, None]
if isinstance(v, dict):
return chekc_pair(v, key, key_value)
return [2, None]
И текст проверки:
data_1 = {
"data": {
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":{
"value":"[email protected]",
"note" : "notice"
},
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
data_2 = {
"data":{
"invoice_id": 17304,
"location_name": "live"
}
}
data_3 = {
"data":{
"invoice_id": 17304,
"location_name": "live",
"owner":{
"email":None,
"name":"Petruxa Stepanovich",
"role":1,
"phone":{
"prefix":"+7",
"number":"000000000"
}
}
}
}
Вывод:
print(chekc_pair(data_1, 'email', 'value'))
print(chekc_pair(data_2, 'email', 'value'))
print(chekc_pair(data_3, 'email', 'value'))
print(chekc_pair(data_4, 'email', 'value'))
#[1, ('email', '[email protected]')]
#[2, None]
#[2, None]
#[1, ('email', '[email protected]')]