중첩 된 사전이 있습니다. 안전하게 가치를 얻는 방법은 하나뿐입니까?
try:
example_dict['key1']['key2']
except KeyError:
pass
아니면 파이썬에는 get()
중첩 사전 과 같은 방법이 있습니까?
답변
get
두 번 사용할 수 있습니다 .
example_dict.get('key1', {}).get('key2')
존재 하거나 존재하지 않으면 반환 None
됩니다 .key1
key2
이것은 여전히 존재하지만 dict (또는 메소드가 있는 dict-like 객체)가 아닌 AttributeError
경우 발생할 수 있습니다 . 설명 할 수없는 경우 게시 한 코드가 대신 나타납니다 .example_dict['key1']
get
try..except
TypeError
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를 사용할 수있는 것과 거의 같은 방식으로 Hasher를 사용할 수 있습니다 dict
. 동일한 방법과 구문을 모두 사용할 수 있으며 해셔는 누락 된 키를 다르게 취급합니다.
정규식 dict
을 다음 Hasher
과 같이 변환 할 수 있습니다 .
hasher = Hasher(example_dict)
쉽게 Hasher
a를 일반으로 변환하십시오 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
one-liner 감소 작동 방식을 이해하기위한 연습으로 다음을 수행했습니다. 그러나 궁극적으로 루프 접근법은 더 직관적 인 것처럼 보입니다.
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')
답변
나는 당신이 시도하는 것이 좋습니다 python-benedict
.
dict
키 경로 지원 등을 제공 하는 서브 클래스입니다.
설치: pip install python-benedict
from benedict import benedict
example_dict = benedict(example_dict, keypath_separator='.')
이제 keypath를 사용하여 중첩 값에 액세스 할 수 있습니다 :
val = example_dict['key1.key2']
# using 'get' method to avoid a possible KeyError:
val = example_dict.get('key1.key2')
또는 키 목록을 사용하여 중첩 값에 액세스 하십시오 .
val = example_dict['key1', 'key2']
# using get to avoid a possible KeyError:
val = example_dict.get(['key1', 'key2'])
GitHub에서 잘 테스트되고 공개 소스입니다 .