sourcecode

중첩된 사전의 값을 가져오는 안전한 방법

copyscript 2023. 1. 30. 22:14
반응형

중첩된 사전의 값을 가져오는 안전한 방법

나는 중첩된 사전을 가지고 있다.안전하게 가치를 전달할 수 있는 방법은 하나뿐입니까?

try:
    example_dict['key1']['key2']
except KeyError:
    pass

은 비단뱀과 같은 .get()스트트 사? ???

하면 .get 2회:

example_dict.get('key1', {}).get('key2')

하면 반환됩니다.None 쪽인가 하면key1 ★★★★★★★★★★★★★★★★★」key2을 사용하다

에도 「」, 「」, 「」가 .AttributeErrorexample_dict['key1']하지만 dict dict(dict)가 있는 (dict)와 )는 .get try..except이 올린 가 'Code'를 됩니다.TypeError instead의 경우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는 의 입니다.dict를 사용할 할 수 .dict수 . 키를 할 뿐입니다. 동일한 메서드와 구문을 모두 사용할 수 있습니다. 해셔스

할 수 .dictHasher음음음같 뭇매하다

hasher = Hasher(example_dict)

Hasherdict마찬가지로 간단합니다.

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

첫 번째 단계에서 빈 사전을 얻을 수 있습니다.

example_dict.get('key1',{}).get('key2')

Yoav의 답변을 바탕으로 더욱 안전한 접근법:

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else None, keys, dictionary)

재귀적 해결법.가장 효율적이지는 않지만 다른 예보다 조금 읽기 쉬우며 펑쿨에 의존하지 않습니다.

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)

한 번 .python-benedict.

은 것은다이 it it이다.dict키 경로 지원 등을 제공하는 서브 클래스입니다.

치::pip install python-benedict

from benedict import benedict

example_dict = benedict(example_dict, keypath_separator='.')

이제 키 경로를 사용하여 중첩된 값에 액세스할 수 있습니다.

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에서 잘 테스트되고 오픈 소스입니다.

https://github.com/fabiocaccamo/python-benedict

주의: 이 프로젝트의 작성자입니다.

리덕션 어프로치는 깔끔하고 짧지만, 단순한 루프가 더 보기 쉽다고 생각합니다.기본 매개 변수도 포함했습니다.

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')

glom 도트 있는 쿼리에도 대응할 수 있는 훌륭한 라이브러리입니다.

In [1]: from glom import glom

In [2]: data = {'a': {'b': {'c': 'd'}}}

In [3]: glom(data, "a.b.c")
Out[3]: 'd'

쿼리 장애에는 정확한 장애 지점을 나타내는 양호한 스택트레이스가 있습니다

In [4]: glom(data, "a.b.foo")
---------------------------------------------------------------------------
PathAccessError                           Traceback (most recent call last)
<ipython-input-4-2a3467493ac4> in <module>
----> 1 glom(data, "a.b.foo")

~/.cache/pypoetry/virtualenvs/neural-knapsack-dE7ihQtM-py3.8/lib/python3.8/site-packages/glom/core.py in glom(target, spec, **kwargs)
   2179 
   2180     if err:
-> 2181         raise err
   2182     return ret
   2183 

PathAccessError: error raised while processing, details below.
 Target-spec trace (most recent last):
 - Target: {'a': {'b': {'c': 'd'}}}
 - Spec: 'a.b.foo'
glom.core.PathAccessError: could not access 'foo', part 2 of Path('a', 'b', 'foo'), got error: KeyError('foo')

default:

In [5]: glom(data, "a.b.foo", default="spam")
Out[5]: 'spam'

★★★의 glom parameterspec spec에 있습니다.를 들어,의 이름에서 할 수 .data:

In [8]: data = {
   ...:     "people": [
   ...:         {"first_name": "Alice", "last_name": "Adams"},
   ...:         {"first_name": "Bob", "last_name": "Barker"}
   ...:     ]
   ...: }

In [9]: glom(data, ("people", ["first_name"]))
Out[9]: ['Alice', 'Bob']

자세한 예는 문서를 참조해 주세요.

pydash를 사용할 수 있습니다.

import pydash as _  #NOTE require `pip install pydash`

_.get(example_dict, 'key1.key2', default='Default')

https://pydash.readthedocs.io/en/latest/api.html

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'

키가 됩니다.None. 이렇게 해서 .default=를 누르다FindDict ":":": " ": ":":

FindDict(person, default='').get('person.name.last') # == doesn't exist, so ''

저는 GenesRus와 unutbu의 답변을 매우 간단하게 수정했습니다.

class new_dict(dict):
    def deep_get(self, *args, default=None):
        _empty_dict = {}
        out = self
        for key in args:
            out = out.get(key, _empty_dict)
        return out if out else default

다음과 같이 동작합니다.

d = new_dict(some_data)
d.deep_get("key1", "key2", "key3", ..., default=some_value)

두 번째 레벨 키를 취득할 경우 다음 작업을 수행할 수 있습니다.

key2_value = (example_dict.get('key1') or {}).get('key2')

3.부터는 Python 3.4를 사용할 수 .부터는with suppress (KeyError)Key 하지 않고 json 합니다.

from contextlib import suppress

with suppress(KeyError):
    a1 = json_obj['key1']['key2']['key3']
    a2 = json_obj['key4']['key5']['key6']
    a3 = json_obj['key7']['key8']['key9']

테크드래곤 제공.상세한 것에 대하여는, https://stackoverflow.com/a/45874251/1189659 를 참조해 주세요.

속성의 깊이를 얻기 위해 이것을 보고 안전하게 네스트하기 위해 다음과 같이 만들었습니다.dict도트 표기법을 사용하여 값을 지정합니다.이게 나한테 효과가 있는 이유는dictsMongoDB 있기 키에 MongoDB가 있지 ..제에서는, s., 「」, 「」, 「」, 「」)를 할 수 .None데이터에는 없기 때문에 함수를 호출할 때 try/except 패턴을 피할 수 있습니다.

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)

그러나 같은 것에 대한 다른 함수도 키가 발견되었는지 여부를 나타내는 부울을 반환하고 예기치 않은 오류를 처리합니다.

'''
json : json to extract value from if exists
path : details.detail.first_name
            empty path represents root

returns a tuple (boolean, object)
        boolean : True if path exists, otherwise False
        object : the object if path exists otherwise None

'''
def get_json_value_at_path(json, path=None, default=None):

    if not bool(path):
        return True, json
    if type(json) is not dict :
        raise ValueError(f'json={json}, path={path} not supported, json must be a dict')
    if type(path) is not str and type(path) is not list:
        raise ValueError(f'path format {path} not supported, path can be a list of strings like [x,y,z] or a string like x.y.z')

    if type(path) is str:
        path = path.strip('.').split('.')
    key = path[0]
    if key in json.keys():
        return get_json_value_at_path(json[key], path[1:], default)
    else:
        return False, default

사용 예:

my_json = {'details' : {'first_name' : 'holla', 'last_name' : 'holla'}}
print(get_json_value_at_path(my_json, 'details.first_name', ''))
print(get_json_value_at_path(my_json, 'details.phone', ''))

(참, 'holla')

(거짓, ')

이미 많은 좋은 답변들이 있지만, 나는 자바스크립트 랜드의 lodash get과 유사한 기능을 생각해냈다.이 기능은 인덱스별 목록에도 접근할 수 있다.

def get(value, keys, default_value = None):
'''
    Useful for reaching into nested JSON like data
    Inspired by JavaScript lodash get and Clojure get-in etc.
'''
  if value is None or keys is None:
      return None
  path = keys.split('.') if isinstance(keys, str) else keys
  result = value
  def valid_index(key):
      return re.match('^([1-9][0-9]*|[0-9])$', key) and int(key) >= 0
  def is_dict_like(v):
      return hasattr(v, '__getitem__') and hasattr(v, '__contains__')
  for key in path:
      if isinstance(result, list) and valid_index(key) and int(key) < len(result):
          result = result[int(key)] if int(key) < len(result) else None
      elif is_dict_like(result) and key in result:
          result = result[key]
      else:
          result = default_value
          break
  return result

def test_get():
  assert get(None, ['foo']) == None
  assert get({'foo': 1}, None) == None
  assert get(None, None) == None
  assert get({'foo': 1}, []) == {'foo': 1}
  assert get({'foo': 1}, ['foo']) == 1
  assert get({'foo': 1}, ['bar']) == None
  assert get({'foo': 1}, ['bar'], 'the default') == 'the default'
  assert get({'foo': {'bar': 'hello'}}, ['foo', 'bar']) == 'hello'
  assert get({'foo': {'bar': 'hello'}}, 'foo.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.0.bar') == 'hello'
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1') == None
  assert get({'foo': [{'bar': 'hello'}]}, 'foo.1.bar') == None
  assert get(['foo', 'bar'], '1') == 'bar'
  assert get(['foo', 'bar'], '2') == None

솔루션에 다른 라이브러리를 사용하는 경우 이 방법이 가장 적합합니다.

https://github.com/maztohir/dict-path

from dict-path import DictPath

data_dict = {
  "foo1": "bar1",
  "foo2": "bar2",
  "foo3": {
     "foo4": "bar4",
     "foo5": {
        "foo6": "bar6",
        "foo7": "bar7",
     },
  }
}

data_dict_path = DictPath(data_dict)
data_dict_path.get('key1/key2/key3')

다음은 unutbu의 함수 답변과 함께 다음과 같은 솔루션을 제공합니다.

  1. python 명명 가이드라인
  2. 파라미터로서의 기본값
  3. try를 사용하지 않고 키가 객체에 있는지 확인만 합니다.
def safe_get(dictionary, *keys, default=None):
    for key in keys:
        if key not in dictionary:
            return default
        dictionary = dictionary[key]
    return dictionary

내 코드에서 유용하다고 생각한 unutbu의 답변을 각색한 것입니다.

example_dict.setdefaut('key1', {}).get('key2')

KeyError를 피하기 위해 key1에 해당 키가 아직 없는 경우 해당 딕셔너리 엔트리가 생성됩니다.저처럼 키쌍을 포함하는 중첩된 사전을 끝내려면 이 방법이 가장 쉬운 해결책인 것 같습니다.

키 중 하나가 누락된 경우 키 오류를 발생시키는 것은 합리적인 일이기 때문에 이를 확인하지 않고 단일 키를 얻을 수도 있습니다.

def get_dict(d, kl):
  cur = d[kl[0]]
  return get_dict(cur, kl[1:]) if len(kl) > 1 else cur

거의 개선되지 않았다reduce목록과 함께 작동하도록 접근합니다.또한 데이터 경로를 배열 대신 점으로 나눈 문자열로 사용합니다.

def deep_get(dictionary, path):
    keys = path.split('.')
    return reduce(lambda d, key: d[int(key)] if isinstance(d, list) else d.get(key) if d else None, keys, dictionary)

내가 사용한 솔루션은 double get과 비슷하지만 다른 로직을 사용하여 Type Error를 회피할 수 있는 추가 기능을 갖추고 있습니다.

    value = example_dict['key1']['key2'] if example_dict.get('key1') and example_dict['key1'].get('key2') else default_value

그러나 사전이 중첩될수록 이 작업은 더 번거로워집니다.

중첩된 사전의 경우/JSON 룩업, 딕터를 사용할 수 있습니다.

pip install 딕터

dict 오브젝트

{
    "characters": {
        "Lonestar": {
            "id": 55923,
            "role": "renegade",
            "items": [
                "space winnebago",
                "leather jacket"
            ]
        },
        "Barfolomew": {
            "id": 55924,
            "role": "mawg",
            "items": [
                "peanut butter jar",
                "waggy tail"
            ]
        },
        "Dark Helmet": {
            "id": 99999,
            "role": "Good is dumb",
            "items": [
                "Shwartz",
                "helmet"
            ]
        },
        "Skroob": {
            "id": 12345,
            "role": "Spaceballs CEO",
            "items": [
                "luggage"
            ]
        }
    }
}

Lonestar 항목을 가져오려면 점으로 구분된 경로를 제공하십시오.

import json
from dictor import dictor

with open('test.json') as data: 
    data = json.load(data)

print dictor(data, 'characters.Lonestar.items')

>> [u'space winnebago', u'leather jacket']

키가 경로에 없는 경우 폴백 값을 제공할 수 있습니다.

대문자와 소문자를 무시하거나 '.' 이외의 문자를 경로 구분자로 사용하는 등 다양한 옵션을 사용할 수 있습니다.

https://github.com/perfecto25/dictor

나는 이 대답을 거의 바꾸지 않았다.리스트와 숫자를 함께 사용하는지 체크하는 것도 추가했습니다.이제 어떤 식으로든 사용할 수 있습니다. deep_get(allTemp, [0], {})또는deep_get(getMinimalTemp, [0, minimalTemperatureKey], 26)기타

def deep_get(_dict, keys, default=None):
    def _reducer(d, key):
        if isinstance(d, dict):
            return d.get(key, default)
        if isinstance(d, list):
            return d[key] if len(d) > 0 else default
        return default
    return reduce(_reducer, keys, _dict)

재귀적 방법(재귀적 방법)

예:

foo = [{'feature_name': 'Sample Creator > Contract Details > Elements of the page',
  'scenarios': [{'scenario_name': 'SC, CD, Elements of the page',
                 'scenario_status': 'failed',
                 'scenario_tags': None,
                 'steps': [{'duration': 0,
                            'name': 'I open application Stage and login by '
                                    'SPT_LOGIN and password SPT_PWD',
                            'status': 'untested'},
                           {'duration': 0,
                            'name': 'I open Sample Creator query page',
                            'status': 'untested'},
                           {'duration': 7.78166389465332,
                            'name': 'I open application Stage and login by '
                                    'SPT_LOGIN and password SPT_PWD',
                            'status': 'passed'},
                           {'duration': 3.985326051712036,
                            'name': 'I open Sample Creator query page',
                            'status': 'passed'},
                           {'duration': 2.9063704013824463,
                            'name': 'Enter value: '
                                    'X-2008-CON-007,X-2011-CON-016 in '
                                    'textarea: project_text_area sleep: 1',
                            'status': 'passed'},
                           {'duration': 4.4447715282440186,
                            'name': 'I press on GET DATA',
                            'status': 'passed'},
                           {'duration': 1.1209557056427002,
                            'name': 'Verify the top table on Contract Details',
                            'status': 'passed'},
                           {'duration': 3.8173601627349854,
                            'name': 'I export contract_details table by offset '
                                    'x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.032956600189209,
                            'name': 'Check data of '
                                    'sc__cd_elements_of_the_page_1 and skip '
                                    'cols None',
                            'status': 'passed'},
                           {'duration': 0.04593634605407715,
                            'name': "Verify 'Number of Substances' column "
                                    'values',
                            'status': 'passed'},
                           {'duration': 0.10199904441833496,
                            'name': 'Substance Sample Details bottom table '
                                    'columns',
                            'status': 'passed'},
                           {'duration': 0.0009999275207519531,
                            'name': 'Verify the Substance Sample Details '
                                    'bottom table',
                            'status': 'passed'},
                           {'duration': 3.8558616638183594,
                            'name': 'I export substance_sample_details table '
                                    'by offset x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.0329277515411377,
                            'name': 'Check data of '
                                    'sc__cd_elements_of_the_page_2 and skip '
                                    'cols None',
                            'status': 'passed'},
                           {'duration': 0.2879970073699951,
                            'name': 'Click on AG-13369',
                            'status': 'passed'},
                           {'duration': 3.800830364227295,
                            'name': 'I export substance_sample_details table '
                                    'by offset x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.0169551372528076,
                            'name': 'Check data of '
                                    'sc__cd_elements_of_the_page_3 and skip '
                                    'cols None',
                            'status': 'passed'},
                           {'duration': 1.7484464645385742,
                            'name': 'Select all cells, table: 2',
                            'status': 'passed'},
                           {'duration': 3.812828779220581,
                            'name': 'I export substance_sample_details table '
                                    'by offset x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.0029594898223877,
                            'name': 'Check data of '
                                    'sc__cd_elements_of_the_page_2 and skip '
                                    'cols None',
                            'status': 'passed'},
                           {'duration': 1.6729373931884766,
                            'name': 'Set window size x:800, y:600',
                            'status': 'passed'},
                           {'duration': 30.145705699920654,
                            'name': 'All scrollers are placed on top 6 and far '
                                    'left 8',
                            'status': 'failed'}]}]},
  {'feature_name': 'Sample Creator > Substance Sample History > Elements of the '
                  'page',
  'scenarios': [{'scenario_name': 'SC, SSH, Elements of the page',
                 'scenario_status': 'passed',
                 'scenario_tags': None,
                 'steps': [{'duration': 0,
                            'name': 'I open application Stage and login by '
                                    'SPT_LOGIN and password SPT_PWD',
                            'status': 'untested'},
                           {'duration': 0,
                            'name': 'I open Sample Creator query page',
                            'status': 'untested'},
                           {'duration': 7.305850505828857,
                            'name': 'I open application Stage and login by '
                                    'SPT_LOGIN and password SPT_PWD',
                            'status': 'passed'},
                           {'duration': 3.500955104827881,
                            'name': 'I open Sample Creator query page',
                            'status': 'passed'},
                           {'duration': 3.0419492721557617,
                            'name': 'Enter value: NOA401800 SYN-NOA '
                                    'A,S4A482070C SYN-ISN-OLD '
                                    'O,S04A482167T,S04A482190Y,CSAA796564,CSCD106701 '
                                    'in textarea: id_text_area sleep: 1',
                            'status': 'passed'},
                           {'duration': 49.567158460617065,
                            'name': 'I press on GET DATA',
                            'status': 'passed'},
                           {'duration': 0.13904356956481934,
                            'name': 'Open substance_sample_history',
                            'status': 'passed'},
                           {'duration': 1.1039845943450928,
                            'name': 'Columns displayed',
                            'status': 'passed'},
                           {'duration': 3.881945848464966,
                            'name': 'I export export_parent_table table by '
                                    'offset x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.0334820747375488,
                            'name': 'Check data of '
                                    'sc__ssh_elements_of_the_page_1 and skip '
                                    'cols None',
                            'status': 'passed'},
                           {'duration': 0.0319981575012207,
                            'name': "Title is 'Additional Details for Marked "
                                    "Rows'",
                            'status': 'passed'},
                           {'duration': 0.08897256851196289,
                            'name': 'Columns displayed (the same as in top '
                                    'table)',
                            'status': 'passed'},
                           {'duration': 25.192569971084595,
                            'name': 'Verify the content of the bottom table',
                            'status': 'passed'},
                           {'duration': 4.308935880661011,
                            'name': 'I export '
                                    'additional_details_for_marked_rows table '
                                    'by offset x:100, y:150',
                            'status': 'passed'},
                           {'duration': 1.0089836120605469,
                            'name': 'Check data of '
                                    'sc__ssh_elements_of_the_page_1 and skip '
                                    'cols None',
                            'status': 'passed'}]}]}]

코드:

def get_keys(_dict: dict, prefix: list):
    prefix += list(_dict.keys())
    return prefix


def _loop_elements(elems:list, prefix=None, limit=None):
    prefix = prefix or []
    limit = limit or 9
    try:
        if len(elems) != 0 and isinstance(elems, list):
            for _ in elems:
                if isinstance(_, dict):
                    get_keys(_, prefix)
                    for item in _.values():
                        _loop_elements(item, prefix, limit)
        return prefix[:limit]
    except TypeError:
        return


>>>goo = _loop_elements(foo,limit=9)
>>>goo
['feature_name', 'scenarios', 'scenario_name', 'scenario_status', 'scenario_tags', 'steps', 'duration', 'name', 'status']
def safeget(_dct, *_keys):
    if not isinstance(_dct, dict): raise TypeError("Is not instance of dict")
    def foo(dct, *keys):
        if len(keys) == 0: return dct
        elif not isinstance(_dct, dict): return None
        else: return foo(dct.get(keys[0], None), *keys[1:])
    return foo(_dct, *_keys)

assert safeget(dict()) == dict()
assert safeget(dict(), "test") == None
assert safeget(dict([["a", 1],["b", 2]]),"a", "d") == None
assert safeget(dict([["a", 1],["b", 2]]),"a") == 1
assert safeget({"a":{"b":{"c": 2}},"d":1}, "a", "b")["c"] == 2

당신이 원하는 대로 할 수 있는 패키지 deepxtract를 작성했습니다.https://github.com/ya332/deepextract 당신은 할 수 있습니다.

from deepextract import deepextract
# Demo: deepextract.extract_key(obj, key)
deeply_nested_dict = {
    "items": {
        "item": {
            "id": {
                "type": {
                    "donut": {
                        "name": {
                            "batters": {
                                "my_target_key": "my_target_value"
                            }
                        }
                    }
                }
            }
        }
    }
}
print(deepextract.extract_key(deeply_nested_dict, "my_target_key") == "my_target_value")

돌아온다

True

하위 명령어로 내려오는 구현은 무시합니다.None값을 지정하지만 다른 항목이 발견되면 TypeError와 함께 실패합니다.

def deep_get(d: dict, *keys, default=None):
    """ Safely get a nested value from a dict

    Example:
        config = {'device': None}
        deep_get(config, 'device', 'settings', 'light')
        # -> None
        
    Example:
        config = {'device': True}
        deep_get(config, 'device', 'settings', 'light')
        # -> TypeError

    Example:
        config = {'device': {'settings': {'light': 'bright'}}}
        deep_get(config, 'device', 'settings', 'light')
        # -> 'light'

    Note that it returns `default` is a key is missing or when it's None.
    It will raise a TypeError if a value is anything else but a dict or None.
    
    Args:
        d: The dict to descend into
        keys: A sequence of keys to follow
        default: Custom default value
    """
    # Descend while we can
    try:
        for k in keys:
            d = d[k]
    # If at any step a key is missing, return default
    except KeyError:
        return default
    # If at any step the value is not a dict...
    except TypeError:
        # ... if it's a None, return default. Assume it would be a dict.
        if d is None:
            return default
        # ... if it's something else, raise
        else:
            raise
    # If the value was found, return it
    else:
        return d

도트를 사용할 수 있습니다.

pip install dotted

from dotted.collection import DottedDict

assert DottedDict(dict(foo=dict(bar="baz")))["foo"]["bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz")))["foo.bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", None) is None
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", "default") == "default"

언급URL : https://stackoverflow.com/questions/25833613/safe-method-to-get-value-of-nested-dictionary

반응형