是否有更可读的方法来检查埋在dict中的密钥是否存在而不是单独检查每个级别?
假设我需要在埋藏的对象中获取此值(示例来自维基数据):
x = s['mainsnak']['datavalue']['value']['numeric-id']
为了确保这不会以运行时错误结束,有必要检查每个级别,如下所示:
if 'mainsnak' in s and 'datavalue' in s['mainsnak'] and 'value' in s['mainsnak']['datavalue'] and 'nurmeric-id' in s['mainsnak']['datavalue']['value']:
x = s['mainsnak']['datavalue']['value']['numeric-id']
我能想到解决这个问题的另一种方法是将它包装成try catch
构造,我觉得这样一个简单的任务也很尴尬。
我正在寻找类似的东西:
x = exists(s['mainsnak']['datavalue']['value']['numeric-id'])
如果所有级别都存在,则返回True
。
答案 0 :(得分:65)
简而言之,使用Python,您必须相信它是easier to ask for forgiveness than permission
try:
x = s['mainsnak']['datavalue']['value']['numeric-id']
except KeyError:
pass
以下是我如何处理嵌套的dict键:
def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
if type(element) is not dict:
raise AttributeError('keys_exists() expects dict as first argument.')
if len(keys) == 0:
raise AttributeError('keys_exists() expects at least two arguments, one given.')
_element = element
for key in keys:
try:
_element = _element[key]
except KeyError:
return False
return True
示例:
data = {
"spam": {
"egg": {
"bacon": "Well..",
"sausages": "Spam egg sausages and spam",
"spam": "does not have much spam in it"
}
}
}
print 'spam (exists): {}'.format(keys_exists(data, "spam"))
print 'spam > bacon (do not exists): {}'.format(keys_exists(data, "spam", "bacon"))
print 'spam > egg (exists): {}'.format(keys_exists(data, "spam", "egg"))
print 'spam > egg > bacon (exists): {}'.format(keys_exists(data, "spam", "egg", "bacon"))
输出:
spam (exists): True
spam > bacon (do not exists): False
spam > egg (exists): True
spam > egg > bacon (exists): True
循环给定element
按给定顺序测试每个键。
我更喜欢我发现的所有variable.get('key', {})
方法,因为它跟在EAFP之后。
除了被调用之外的函数:keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)
。至少需要两个参数,元素和一个键,但您可以添加所需的键数。
如果您需要使用某种地图,您可以执行以下操作:
expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)
答案 1 :(得分:10)
您可以使用.get
默认值:
s.get('mainsnak', {}).get('datavalue', {}).get('value', {}).get('numeric-id')
但这几乎肯定不如使用try / except。
答案 2 :(得分:5)
尝试/除了似乎是最诡计多端的方式。
以下递归函数应该有效(如果在dict中找不到其中一个键,则返回None):
def exists(obj, chain):
_key = chain.pop(0)
if _key in obj:
return exists(obj[_key], chain) if chain else obj[_key]
myDict ={
'mainsnak': {
'datavalue': {
'value': {
'numeric-id': 1
}
}
}
}
result = exists(myDict, ['mainsnak', 'datavalue', 'value', 'numeric-id'])
print(result)
>>> 1
答案 3 :(得分:5)
dictionary = {
"main_key": {
"sub_key": "value",
},
}
if sub_key_value := dictionary.get("main_key", {}).get("sub_key"):
print(f"The key 'sub_key' exists in dictionary[main_key] and it's value is {sub_key_value}")
else:
print("Key 'sub_key' doesn't exists")
答案 4 :(得分:3)
您可以使用 onDrop(files) {
let f = files.map(file => ({
name: file.name,
preview: file.preview
}));
this.setState({
files: this.state.files.length > 0 ? [...this.state.files, ...f] : f,
});
}
来检查是否存在:http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
或获取值(您甚至可以设置默认值-如果不存在则返回):http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
这里是一个例子:
pydash
答案 5 :(得分:3)
接受的 answer 是一个很好的方法,但这是另一种方法。如果你最终不得不经常这样做,那么打字会少一点,眼睛也容易一点(在我看来)。它也不需要像其他一些答案那样的任何额外的包依赖项。没有比较性能。
import functools
def haskey(d, path):
try:
functools.reduce(lambda x, y: x[y], path.split("."), d)
return True
except KeyError:
return False
# Throwing in this approach for nested get for the heck of it...
def getkey(d, path, *default):
try:
return functools.reduce(lambda x, y: x[y], path.split("."), d)
except KeyError:
if default:
return default[0]
raise
用法:
data = {
"spam": {
"egg": {
"bacon": "Well..",
"sausages": "Spam egg sausages and spam",
"spam": "does not have much spam in it",
}
}
}
(Pdb) haskey(data, "spam")
True
(Pdb) haskey(data, "spamw")
False
(Pdb) haskey(data, "spam.egg")
True
(Pdb) haskey(data, "spam.egg3")
False
(Pdb) haskey(data, "spam.egg.bacon")
True
来自 this 问题答案的原始灵感。
答案 6 :(得分:2)
我建议您使用python-benedict
,它是具有完整键路径支持和许多实用程序方法的可靠python dict子类。
您只需要投射现有的字典:
s = benedict(s)
现在您的字典具有完整的密钥路径支持,您可以使用in运算符来检查密钥是否以pythonic方式存在:
if 'mainsnak.datavalue.value.numeric-id' in s:
# do stuff
这里是库存储库和文档: https://github.com/fabiocaccamo/python-benedict
答案 7 :(得分:1)
在这种情况下,我写了一个名为dataknead
的数据解析库,主要是因为我对Wikidata API返回的JSON感到沮丧。
有了该库,您可以执行类似的操作
from dataknead import Knead
numid = Knead(s).query("mainsnak/datavalue/value/numeric-id").data()
if numid:
# Do something with `numeric-id`
答案 8 :(得分:1)
try / except方法是最干净的,没有竞争。但是,它也算作我的IDE中的异常,这会在调试时停止执行。
此外,我不喜欢将异常用作方法内控制语句,这实际上是try / catch发生的事情。
这是一个不使用递归的简短解决方案,它支持默认值:
def chained_dict_lookup(lookup_dict, keys, default=None):
_current_level = lookup_dict
for key in keys:
if key in _current_level:
_current_level = _current_level[key]
else:
return default
return _current_level
答案 9 :(得分:1)
如果您可以测试对象路径的字符串表示形式,那么此方法可能对您有用:
{{1}}
答案 10 :(得分:1)
我遇到了同样的问题,最近出现了python lib:
https://pypi.org/project/dictor/
https://github.com/perfecto25/dictor
所以在您的情况下:
from dictor import dictor
x = dictor(s, 'mainsnak.datavalue.value.numeric-id')
个人笔记:
我不喜欢'dictor'这个名字,因为它并不能暗示它实际上在做什么。所以我像这样使用它:
from dictor import dictor as extract
x = extract(s, 'mainsnak.datavalue.value.numeric-id')
没有比extract
更好的命名方式了。如果您提出更可行的命名方式,请随时发表评论。 safe_get
,robust_get
不适合我的情况。
答案 11 :(得分:1)
另一种方式:
def does_nested_key_exists(dictionary, nested_key):
exists = nested_key in dictionary
if not exists:
for key, value in dictionary.items():
if isinstance(value, dict):
exists = exists or does_nested_key_exists(value, nested_key)
return exists
答案 12 :(得分:-1)
有很多很好的答案。这是我对它的谦虚看法。还添加了对字典数组的检查。请注意,我没有检查参数的有效性。我在上面使用了部分 Arnot 的代码。我添加了这个答案,因为我有一个用例需要检查我的数据中的数组或字典。 代码如下:
def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
retval=False
if isinstance(element,dict):
for key,value in element.items():
for akey in keys:
if element.get(akey) is not None:
return True
if isinstance(value,dict) or isinstance(value,list):
retval= keys_exists(value, *keys)
elif isinstance(element, list):
for val in element:
if isinstance(val,dict) or isinstance(val,list):
retval=keys_exists(val, *keys)
return retval