如何pythonically多次使用.get()?

时间:2017-07-10 16:12:12

标签: python dictionary

使用<dict>.get('<key>') 多次来访问dict的不同级别的最强 pythonic / efficient 方法是什么?< / p>

(这些例子故意短,但想象更多的键和更长的原始词典)

示例

而不是:

    complete_data = {'name': 'bob',
                     'age':'22',
                     'items': [{'subitem':1,'another subitem':2}, 123, 456]}

    required_data['name'] = complete_data['name']

    required_data['another subitem'] = complete_data['items'][0]['another subitem']

我们可以使用这样的东西:

    complete_data = {'name': 'bob', 'age':'22', 'other stuff': 'some stuff'}

    desired_keys = ['name','age']

    for i in range(len(desired_keys)):
        required_data[desired_keys[i]] = complete_data[desired_keys[i]]

(但要找到像complete_data['items'][0]['another subitem']这样的字体里面更深(?)的东西)

某些上下文:API发送的信息超出了我的需要。信息打包为dict,其中包含更多子序列和列表。我试图尽可能有效地提取信息,因为我必须重复这一百万次以上。我也希望尽可能高效地编写代码,因为我必须为多个API修改它。

2 个答案:

答案 0 :(得分:6)

您可以将密钥存储在列表中,然后编写一个函数来为您执行项目查找:

from functools import reduce
import operator

def lookup(container, keys):
    return reduce(operator.getitem, keys, container)

这样,complete_data['items'][0]['another subitem']变为

lookup(complete_data, ['items', 0, 'another subitem'])

或者,这是一个故障安全实现:

def lookup(container, keys, default=None):
    try:
        return reduce(operator.getitem, keys, container)
    except (IndexError, KeyError):
        return default

然后您可以使用它轻松收集所需的所有数据:

desired_keys=  {'name': ['name'],
                'another subitem': ['items', 0, 'another subitem']}

required_data= {}
for key, keys in desired_keys.items():
    required_data[key]= lookup(complete_data, keys)

print(required_data)
# output: {'name': 'bob', 'another subitem': 2}

答案 1 :(得分:2)

简单索引方法

这是许多Python程序员对此有不同意见的事情,但是如果输入格式不正确,那么它归结为你想要代码的容错程度。如果你肯定输入遵循该结构,你可以简单地使用链式索引:

try:
    sub_item_one = data['items'][0]['subitem']
except (KeyError, IndexError) as e:
    print("Unexpected structure, {}".format(e))

如果密钥/索引不存在,此访问模式将抛出KeyErrorIndexError,因此您可以捕获这些异常并打印/执行您希望缓解的内容。

关键路径方法

存在“密钥路径”的概念,其基本上是如何访问嵌套在字典/列表结构中的值的描述的列表。上面的例子是("items", 0, "subitem")的关键路径。我使用元组来表示它,但它可以是任何有序的序列。我们可以编写一个简单的方法,它采用关键路径和结构,并安全地提取值。我们也可以像default方法一样提供dict.get() kwarg,因此如果内部发生KeyErrorIndexError,则可以返回默认值。

def get_key_path_value(key_path, obj, default=None):
    if not key_path:
        return obj
    try:
        for key in key_path:
            obj = obj[key]
    except (KeyError, IndexError):
        return default
    return obj

data = {
    "thing": [
        {"key": "value"},
        {"key2": "val2"}
    ],
}

print(get_key_path_value(("thing", 1, "key2"), data))
# val2
print(get_key_path_value(("thing", 0), data))
# {'key': 'value'}
print(get_key_path_value(("thing", 1, "key_none"), data))
# None

全部放在一起

由于实际问题是在结构中的不同嵌套级别获取多个键,因此我们可以设置我们的本地键名称到我们想要提取的键路径的映射。

complete_data = {'name': 'bob',
                 'age': '22',
                 'items': [{'subitem': 1, 'another subitem': 2}, 123, 456]}

key_mapping = {
    "name": ("name",),
    "sub_item_one": ("items", 0, "subitem"),
}

pulled_data = {}
for key, key_path in key_mapping.iteritems():
    pulled_data[key] = get_key_path_value(key_path, complete_data)

print(pulled_data)
# {'sub_item_one': 1, 'name': 'bob'}