【问题标题】:python approach nested dictionary with 1 variablepython方法具有1个变量的嵌套字典
【发布时间】:2020-01-16 09:04:42
【问题描述】:

我发现这种问题很难命名,但它一定很简单,而且我缺少一些基本的东西。

假设我有以下 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")

【问题讨论】:

  • 尝试使用递归函数。(如果返回的元素是字典,则再次调用该函数,直到你有一个非字典对象)
  • 迭代方法可能会以一种丑陋的方式解决它。我想要更简单和 Pythoic 的东西。我将编写该解决方案作为示例
  • 然后尝试使用eval函数link
  • dct[field] vs foo(field) - 看起来你并没有真正通过拥有这个功能获得太多
  • 或者可能是星号运算符,因此您可以将任意数量的参数传递给函数。

标签: python json elasticsearch


【解决方案1】:

您可以使用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'

【讨论】:

  • 这确实解决了这个问题,但我的目标是更多的 Pythonic
  • 定义“更多pythonic”。
  • 如果问题只是 1 个键,我们将使用 1 个参数和 1 行来解决它。所以 1 行解决方案。但仔细想想,我们可能只是构建一个辅助函数来获取我们想要的嵌套键......
  • 我认为单线解决方案是不可能的。
  • 你想告诉我 python 没有实现某种函数来获取变量列表并且 python 字典为该嵌套键返回正确的值? :>
【解决方案2】:

此函数将递归查找传递给它的字典中的键 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】:

尝试做:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    • 2018-05-31
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多