代码之家  ›  专栏  ›  技术社区  ›  Eran Moshe

python方法1变量嵌套字典

  •  1
  • Eran Moshe  · 技术社区  · 6 年前

    我发现这类问题很难命名,但肯定是个简单的问题,我遗漏了一些基本的东西。

    假设我有以下python dict():

    import json
    
    dct = dict()
    dct['hits'] = dict()
    dct['hits']['hits'] = dict()
    dct['hits']['hits']['a'] = 'b'
    dct['hits']['hits']['b'] = 'c'
    dct['aggregations'] = dict()
    dct['aggregations']['a'] = 1
    dct['aggregations']['b'] = 2
    
    print(json.dumps(dct, indent=2))
    
    {
      "hits": {
        "hits": {
          "a": "b",
          "b": "c"
        }
      },
      "aggregations": {
        "a": 1,
        "b": 2
      }
    }
    

    这看起来可能很熟悉,因为它是elasticsearch返回结果的结构。

    我正在构建一个使用该结果的函数。但有时我想接近 dct['hits']['hits'] 有时我想接近 dct['aggregations'] .

    自然地,我会使用一个带有变量的函数来建议我要访问哪个字段,如下所示:

    def foo(field):
        return dct[field]
    

    如果 field='aggregations' 一切都很好。但如果我想让这个领域 ['hits']['hits'] ?


    一种解决方法(但很难看),迭代方法:

    def foo(fields=('hits','hits')):
        wanted = dct
        for field in fields:
            wanted = wanted[field]
        return wanted
    
    a = foo()
    a
    Out[47]: {'a': 'b', 'b': 'c'}
    a = foo(('aggregations',))
    a
    Out[51]: {'a': 1, 'b': 2}
    

    我试图修改的实际函数:

    def execute_scroll_query(es_client, query, indexes):
        try:
            response = es_client.search(index=indexes, scroll='2m', size=1000, body=query)
            scroll_size = len(response['hits']['hits'])
            sid = response['_scroll_id']
            while scroll_size > 0:
                try:
                    for hit in response['hits']['hits']:
                        yield hit
                    response = es_client.scroll(scroll_id=sid, scroll='2m')
                    sid = response['_scroll_id']
                    scroll_size = len(response['hits']['hits'])
                except Exception:
                    print("Unexpected Exception while scrolling")
        except Exception:
            print("Unexpected Exception while fetching")
    
    3 回复  |  直到 6 年前
        1
  •  1
  •   DYZ    6 年前

    你可以使用 functools.reduce ,但在幕后,它使用的是迭代,并且可能不如显式迭代有效:

    from functools import reduce
    
    def foo(d, keys):
        return reduce(lambda x, y: x[y], keys, d)
    
    foo(dct, ['hits', 'hits', 'a'])
    #'b'
    
        2
  •  1
  •   Iain Shelvington    6 年前

    此函数将递归查找传递给它的字典中的键。 d 并返回上次成功的查找

    def get_nested(d, key):
        result = d.get(key)
        if isinstance(result, dict):
            return result or get_nested(result, key)
        return result
    

    可以这样称呼

    get_nested(dct, 'hits')
    get_nested(dct, 'aggregations')
    
        3
  •  0
  •   Dipen Dadhaniya    6 年前

    尝试做:

    dct = dict()
    dct['hits'] = dict()
    dct['hits']['hits'] = dict()
    dct['hits']['hits']['a'] = 'b'
    dct['hits']['hits']['b'] = 'c'
    dct['aggregations'] = dict()
    dct['aggregations']['a'] = 1
    dct['aggregations']['b'] = 2
    
    
    def foo(dct, *fields):
        n = len(fields)
    
        for idx in range(n):
            if idx == n - 1:
                return dct[fields[idx]]
            else:
                dct = dct[fields[idx]]
    
    
    print(foo(dct, 'hits'))    
    print(foo(dct, 'hits', 'hits'))
    print(foo(dct, 'hits', 'hits', 'a'))
    print(foo(dct, 'aggregations'))
    print(foo(dct, 'aggregations', 'a'))