Python 检查字典中是否存在嵌套键的优雅方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43491287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Elegant way to check if a nested key exists in a dict?
提问by loomi
Is there are more readable way to check if a key buried in a dict exists without checking each level independently?
是否有更易读的方法来检查是否存在 dict 中埋藏的键而不独立检查每个级别?
Lets say I need to get this value in a object buried (example taken from Wikidata):
假设我需要在一个埋藏的对象中获取这个值(示例取自维基数据):
x = s['mainsnak']['datavalue']['value']['numeric-id']
To make sure that this does not end with a runtime error it is necessary to either check every level like so:
为了确保这不会以运行时错误结束,有必要像这样检查每个级别:
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']
The other way I can think of to solve this is wrap this into a try catch
construct which I feel is also rather awkward for such a simple task.
我能想到的解决这个问题的另一种方法是将它包装成一个try catch
结构,我觉得对于这样一个简单的任务来说也很尴尬。
I am looking for something like:
我正在寻找类似的东西:
x = exists(s['mainsnak']['datavalue']['value']['numeric-id'])
which returns True
if all levels exists.
True
如果所有级别都存在,则返回。
回答by Arount
To be brief, with Python you must trust it is easier to ask for forgiveness than permission
简而言之,使用 Python,您必须相信请求宽恕比许可更容易
try:
x = s['mainsnak']['datavalue']['value']['numeric-id']
except KeyError:
pass
The answer
答案
Here is how I deal with nested dict keys:
这是我处理嵌套字典键的方法:
def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
if not isinstance(element, 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
Example:
例子:
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"))
Output:
输出:
spam (exists): True
spam > bacon (do not exists): False
spam > egg (exists): True
spam > egg > bacon (exists): True
It loop in given element
testing each key in given order.
它以给element
定的顺序循环测试每个键。
I prefere this to all variable.get('key', {})
methods I found because it follows EAFP.
我更喜欢这个而不是variable.get('key', {})
我找到的所有方法,因为它遵循EAFP。
Function except to be called like: keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)
. At least two arguments are required, the element and one key, but you can add how many keys you want.
函数除了被调用如下:keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)
。至少需要两个参数,元素和一个键,但您可以添加所需的键数。
If you need to use kind of map, you can do something like:
如果您需要使用某种地图,您可以执行以下操作:
expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)
回答by Daniel Roseman
You could use .get
with defaults:
您可以使用.get
默认值:
s.get('mainsnak', {}).get('datavalue', {}).get('value', {}).get('numeric-id')
but this is almost certainly less clear than using try/except.
但这几乎肯定不如使用 try/except 清楚。
回答by Maurice Meyer
Try/except seems to be most pythonic way to do that.
The following recursive function should work (returns None if one of the keys was not found in the dict):
Try/except 似乎是最pythonic 的方式来做到这一点。
下面的递归函数应该可以工作(如果在字典中找不到键之一,则返回 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
回答by Fabio Caccamo
I suggest you to use python-benedict
, a solid python dict subclass with full keypath support and many utility methods.
我建议您使用python-benedict
,一个具有完整键路径支持和许多实用方法的可靠 python dict 子类。
You just need to cast your existing dict:
你只需要转换你现有的字典:
s = benedict(s)
Now your dict has full keypath support and you can check if the key exists in the pythonic way, using the in operator:
现在您的 dict 具有完整的 keypath 支持,您可以使用 in 运算符检查密钥是否以 pythonic 方式存在:
if 'mainsnak.datavalue.value.numeric-id' in s:
# do stuff
Here the library repository and the documentation: https://github.com/fabiocaccamo/python-benedict
这里是库存储库和文档:https: //github.com/fabiocaccamo/python-benedict
回答by Alexander
You can use pydash
to check if exists: http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
您可以使用pydash
检查是否存在:http: //pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Or get the value (you can even set default - to return if doesn't exist): http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
或获取值(您甚至可以设置默认值 - 如果不存在则返回):http: //pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Here is an example:
下面是一个例子:
>>> get({'a': {'b': {'c': [1, 2, 3, 4]}}}, 'a.b.c[1]')
2
回答by Houen
The try/except way is the most clean, no contest. However, it also counts as an exception in my IDE, which halts execution while debugging.
try/except 方式是最干净的,没有竞争。但是,它在我的 IDE 中也算作异常,它在调试时停止执行。
Furthermore, I do not like using exceptions as in-method control statements, which is essentially what is happening with the try/catch.
此外,我不喜欢使用异常作为方法内控制语句,这本质上是 try/catch 发生的事情。
Here is a short solution which does not use recursion, and supports a default value:
这是一个不使用递归并支持默认值的简短解决方案:
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
回答by geotheory
If you can suffer testing a string representation of the object path then this approach might work for you:
如果您可以测试对象路径的字符串表示,那么这种方法可能适合您:
def exists(str):
try:
eval(str)
return True
except:
return False
exists("lst['sublist']['item']")
回答by darkless
I had the same problem and recent python lib popped up:
https://pypi.org/project/dictor/
https://github.com/perfecto25/dictor
我遇到了同样的问题,最近弹出了 python 库:
https: //pypi.org/project/dictor/
https://github.com/perfecto25/dictor
So in your case:
所以在你的情况下:
from dictor import dictor
x = dictor(s, 'mainsnak.datavalue.value.numeric-id')
Personal note:
I don't like 'dictor' name, since it doesn't hint what it actually does. So I'm using it like:
个人说明:
我不喜欢“独裁者”的名字,因为它并没有暗示它实际做什么。所以我像这样使用它:
from dictor import dictor as extract
x = extract(s, 'mainsnak.datavalue.value.numeric-id')
Couldn't come up with better naming than extract
. Feel free to comment, if you come up with more viable naming. safe_get
, robust_get
didn't felt right for my case.
想不出比extract
. 如果您想出更可行的命名,请随时发表评论。safe_get
,robust_get
感觉不适合我的情况。
回答by Husky
I wrote a data parsing library called dataknead
for cases like this, basically because i got frustrated by the JSON the Wikidata API returns as well.
我写了一个数据解析库来调用dataknead
这种情况,主要是因为我对 Wikidata API 返回的 JSON 感到沮丧。
With that library you could do something like this
有了那个图书馆,你可以做这样的事情
from dataknead import Knead
numid = Knead(s).query("mainsnak/datavalue/value/numeric-id").data()
if numid:
# Do something with `numeric-id`
回答by Lucas Vazquez
python 3.8
蟒蛇 3.8
dictionary = {
"key_1": {
"key_2": "Hi",
},
}
if key_exists := dictionary.get("key_1", {}).get("key_2"):
print(f"The key 'key_2' exists in dictionary[key_1] and it's value is {key_exists}")
else:
print("Key 'key_2' doesn't exists")