【发布时间】:2022-01-13 00:53:50
【问题描述】:
我有一个从 api 响应中读取的可变长度嵌套字典,我希望能够读取可以深度嵌套的键的值。
例如:
responses = {'animal': {'name': 'lassy'}}
print(responses['animal']['name'])
但是我不知道响应中字典的长度,我可能会被要求找到“foo.bar.foo.bar”的值
有没有办法设置我的代码,无论响应的长度如何,我都可以访问所需的值?
【问题讨论】:
我有一个从 api 响应中读取的可变长度嵌套字典,我希望能够读取可以深度嵌套的键的值。
例如:
responses = {'animal': {'name': 'lassy'}}
print(responses['animal']['name'])
但是我不知道响应中字典的长度,我可能会被要求找到“foo.bar.foo.bar”的值
有没有办法设置我的代码,无论响应的长度如何,我都可以访问所需的值?
【问题讨论】:
循环遍历键列表,将当前关卡的引用替换为下一个键的值。
responses = {'animal': {'name': 'lassy'}}
keys = ['animal', 'name']
r = responses
for key in keys:
r = r[key]
print(r)
【讨论】:
我猜你可以只拆分响应 <string>.split(".") 然后使用循环你可以通过t
query = "animal.name"
responses = {'animal': {'name': 'lassy'}}
query_array = query.split('.')
result = response;
for key in query_array:
if key not in result:
print('error')
break
result = result[key]
print(result)
【讨论】:
一个很好的方法可能是编写一个通用的类:
from typing import Hashable
class CompoundKeyDict(dict):
def __getitem__(self, item):
try:
__ = iter(item)
if isinstance(item, Hashable):
raise TypeError()
value = None
for key in item:
value = super().__getitem__(key) if value is None else value[key]
return value
except TypeError:
return super().__getitem__(item)
responses = CompoundKeyDict({'animal': {'name': 'lassy'}})
# this still works
print(responses['animal'])
# but this now also works
print(responses[['animal', 'name']])
# so you can do something like this as well
print(responses['animal.name'.split('.')])
print(isinstance(responses, dict))
有了该类可用,您可以使用任何dict(比如d)并使用列表、生成器或任何其他可迭代的方法访问它,方法是将其转换为CompoundKeyDict 和d = CompoundKeyDict(d)。
关于它如何/为什么起作用的一些评论:
__getitem__ 被覆盖以更改访问 dict 的标准行为,但由于不可哈希的迭代不是有效的键(因为它们是可变的),这只会影响您需要的情况。__ = iter(item) 对于任何不可迭代的内容,此行将失败并显示 TypeError;对于任何可迭代但也可散列(如字符串或元组)的东西,下一行仍将引发 TypeError;所以你只剩下可迭代但不可散列的键,如列表或生成器。super().__getitem__(key)是必填项,这调用了dict的原__getitem__;调用 self[key] 会导致无限循环print(responses[('animal', 'name')]) 只会抛出 KeyError,除非有一个条目以 ('animal', 'name') 作为键。结果:
{'name': 'lassy'}
lassy
lassy
True
【讨论】:
你需要递归:
def myprint(d):
for k, v in d.items():
if isinstance(v, dict):
myprint(v)
else:
print("{0} : {1}".format(k, v))
您可以在这里找到完整的答案: Loop through all nested dictionary values?
【讨论】: