중첩 된 사전의 값을 가져 오는 Python 안전한 방법
중첩 된 사전이 있습니다. 가치를 안전하게 얻을 수있는 유일한 방법이 있습니까?
try:
example_dict['key1']['key2']
except KeyError:
pass
아니면 파이썬 get()
에 중첩 사전 과 같은 방법이 있습니까?
get
두 번 사용할 수 있습니다 .
example_dict.get('key1', {}).get('key2')
None
둘 중 하나가 key1
있거나 key2
존재하지 않으면 반환 됩니다 .
이것은 여전히 AttributeError
if example_dict['key1']
exist를 발생 시킬 수 있지만 dict (또는 get
메서드가 있는 dict-like 객체)는 아닙니다 . try..except
게시 한 코드 는 구독 할 수없는 TypeError
경우 대신 a 를 발생 example_dict['key1']
시킵니다.
또 다른 차이점은 try...except
첫 번째 누락 된 키 직후 단락 이 발생한다는 것 입니다. get
호출 체인은 그렇지 않습니다.
구문을 보존하고 example_dict['key1']['key2']
싶지만 KeyErrors를 발생시키지 않도록하려면 Hasher 레시피를 사용할 수 있습니다 .
class Hasher(dict):
# https://stackoverflow.com/a/3405143/190597
def __missing__(self, key):
value = self[key] = type(self)()
return value
example_dict = Hasher()
print(example_dict['key1'])
# {}
print(example_dict['key1']['key2'])
# {}
print(type(example_dict['key1']['key2']))
# <class '__main__.Hasher'>
키가 없으면 빈 Hasher를 반환합니다.
당신 Hasher
의 서브 클래스 이기 때문에 dict
당신이 사용할 수있는 것과 거의 같은 방식으로 Hasher를 사용할 수 있습니다 dict
. 모든 동일한 방법과 구문을 사용할 수 있으며 Hasher는 누락 된 키를 다르게 취급합니다.
정규식 dict
을 다음 Hasher
과 같이 변환 할 수 있습니다 .
hasher = Hasher(example_dict)
a Hasher
를 일반 dict
으로 쉽게 변환하십시오 .
regular_dict = dict(hasher)
또 다른 대안은 도우미 함수에서 추함을 숨기는 것입니다.
def safeget(dct, *keys):
for key in keys:
try:
dct = dct[key]
except KeyError:
return None
return dct
따라서 나머지 코드는 상대적으로 가독성이 좋습니다.
safeget(example_dict, 'key1', 'key2')
python reduce를 사용할 수도 있습니다 .
def deep_get(dictionary, *keys):
return reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)
이 모든 답변과 제가 만든 작은 변경 사항을 결합하면이 기능이 유용 할 것이라고 생각합니다. 안전하고 빠르고 쉽게 유지 보수가 가능합니다.
def deep_get(dictionary, keys, default=None):
return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
예 :
>>> from functools import reduce
>>> def deep_get(dictionary, keys, default=None):
... return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
...
>>> person = {'person':{'name':{'first':'John'}}}
>>> print (deep_get(person, "person.name.first"))
John
>>> print (deep_get(person, "person.name.lastname"))
None
>>> print (deep_get(person, "person.name.lastname", default="No lastname"))
No lastname
>>>
Yoav의 답변을 바탕으로 더욱 안전한 접근 방식 :
def deep_get(dictionary, *keys):
return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else None, keys, dictionary)
재귀 솔루션. 가장 효율적은 아니지만 다른 예제보다 좀 더 읽기 쉽고 functools에 의존하지 않습니다.
def deep_get(d, keys):
if not keys or d is None:
return d
return deep_get(d.get(keys[0]), keys[1:])
예
d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code']) # => 200
deep_get(d, ['garbage', 'status_code']) # => None
더 세련된 버전
def deep_get(d, keys, default=None):
"""
Example:
d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code']) # => 200
deep_get(d, ['garbage', 'status_code']) # => None
deep_get(d, ['meta', 'garbage'], default='-') # => '-'
"""
assert type(keys) is list
if d is None:
return default
if not keys:
return d
return deep_get(d.get(keys[0]), keys[1:], default)
감소 접근 방식은 깔끔하고 짧지 만 간단한 루프가 더 쉽게 찾을 수 있다고 생각합니다. 기본 매개 변수도 포함했습니다.
def deep_get(_dict, keys, default=None):
for key in keys:
if isinstance(_dict, dict):
_dict = _dict.get(key, default)
else:
return default
return _dict
한 줄 줄임이 어떻게 작동하는지 이해하기위한 연습으로 다음을 수행했습니다. 그러나 궁극적으로 루프 접근 방식은 나에게 더 직관적으로 보입니다.
def deep_get(_dict, keys, default=None):
def _reducer(d, key):
if isinstance(d, dict):
return d.get(key, default)
return default
return reduce(_reducer, keys, _dict)
용법
nested = {'a': {'b': {'c': 42}}}
print deep_get(nested, ['a', 'b'])
print deep_get(nested, ['a', 'b', 'z', 'z'], default='missing')
dict를 래핑하고 키를 기반으로 검색 할 수있는 간단한 클래스 :
class FindKey(dict):
def get(self, path, default=None):
keys = path.split(".")
val = None
for key in keys:
if val:
if isinstance(val, list):
val = [v.get(key, default) if v else None for v in val]
else:
val = val.get(key, default)
else:
val = dict.get(self, key, default)
if not val:
break
return val
예를 들면 :
person = {'person':{'name':{'first':'John'}}}
FindDict(person).get('person.name.first') # == 'John'
If the key doesn't exist, it returns None
by default. You can override that using a default=
key in the FindDict
wrapper -- for example`:
FindDict(person, default='').get('person.name.last') # == doesn't exist, so ''
for a second level key retrieving, you can do this:
key2_value = (example_dict.get('key1') or {}).get('key2')
After seeing this for deeply getting attributes, I made the following to safely get nested dict
values using dot notation. This works for me because my dicts
are deserialized MongoDB objects, so I know the key names don't contain .
s. Also, in my context, I can specify a falsy fallback value (None
) that I don't have in my data, so I can avoid the try/except pattern when calling the function.
from functools import reduce # Python 3
def deepgetitem(obj, item, fallback=None):
"""Steps through an item chain to get the ultimate value.
If ultimate value or path to value does not exist, does not raise
an exception and instead returns `fallback`.
>>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1}}}}
>>> deepgetitem(d, 'snl_final.about._icsd.icsd_id')
1
>>> deepgetitem(d, 'snl_final.about._sandbox.sbx_id')
>>>
"""
def getitem(obj, name):
try:
return obj[name]
except (KeyError, TypeError):
return fallback
return reduce(getitem, item.split('.'), obj)
An adaptation of unutbu's answer that I found useful in my own code:
example_dict.setdefaut('key1', {}).get('key2')
It generates a dictionary entry for key1 if it does not have that key already so that you avoid the KeyError. If you want to end up a nested dictionary that includes that key pairing anyway like I did, this seems like the easiest solution.
Since raising an key error if one of keys is missing is a reasonable thing to do, we can even not check for it and get it as single as that:
def get_dict(d, kl):
cur = d[kl[0]]
return get_dict(cur, kl[1:]) if len(kl) > 1 else cur
참고URL : https://stackoverflow.com/questions/25833613/python-safe-method-to-get-value-of-nested-dictionary
'Programming' 카테고리의 다른 글
Java에서 뮤텍스와 세마포어는 무엇입니까? (0) | 2020.08.08 |
---|---|
Ruby : 문자열의 첫 번째 문자를 얻는 방법 (0) | 2020.08.08 |
MySQL Insert Where 쿼리 (0) | 2020.08.08 |
WKWebView에서 사용할 쿠키를 설정할 수 있습니까? (0) | 2020.08.08 |
스위치 내부에서 루프를 해제하는 방법은 무엇입니까? (0) | 2020.08.08 |