Python:使用列表安全地访问字典?
Python: Safe dictionary access with lists?
是否有一种无异常的方式来访问包含列表的字典中的值。例如,如果我有:
data = {
"object_1": {
"object_2": {
"list": [
{
"property": "hello"
}
]
}
}
}
如何安全地访问路径 data['object_1']['object_2']['list'][0]['property']
(即 return 如果无法在不抛出错误的情况下访问某些默认值)?我试图避免将它们包装在 try-except
中。我看过基于 reduce 的方法,但它没有考虑到字典中的列表。
在 JS 中,我可以这样写:
data.object_1?.object_2?.list[0]?.property ?? 'nothing_found'
Python中有类似的东西吗?
对于dict
你可以使用get
方法。对于列表,您可以注意索引:
data.get('object_1', {}).get('object_2', {}).get('list', [{}])[0].get('property', default)
这有点尴尬,因为它会为每次调用创建一个新的临时命令或丢失 get
。对于没有等效方法的列表也不是超级安全。
您也可以将 getter 包装在一个小例程中以支持列表,但这并不值得。您最好编写一个 one-off 实用函数,该函数使用异常处理或初步检查来处理您想要响应的情况:
def get(obj, *keys, default=None):
for key in keys:
try:
obj = obj[key]
except KeyError, IndexError:
return default
return obj
异常处理与其他方式相比有几个巨大的优势。一方面,您不必根据对象是字典还是列表对键进行单独检查。另一方面,您可以支持几乎任何其他支持 __getitem__
索引的合理类型。为了表明我的意思,这里是请求许可而不是宽恕的方法:
from collections.abc import Mapping, Sequence
from operator import index
def get(obj, *keys, default=None):
for key in keys:
if isinstance(obj, Mapping):
if key not in obj:
return default
elif isinstance(obj, Sequence):
try:
idx = index(key)
except TypeError:
return default
if len(obj) <= idx or len(obj) < -idx:
return default
obj = obj[key]
return obj
观察检查是多么尴尬和 error-prone。尝试传入一个自定义对象而不是 list
,或者一个不是整数的键。在 Python 中,小心使用异常是你的朋友,请求宽恕而不是许可是 pythonic 的原因是有原因的。
呃。是的,访问这样的 JSON 数据结构真是太糟糕了,
有点尴尬。
Glom 救援!
有两种获胜方式:
您可以只指定 ... , default=None)
以避免异常,..或..
使用Coalesce
。
print(glom(data, {'object_1.object_2.list': ['property']}, default=None))
有一种方法可以做到这一点,但它会涉及 get
方法,并且会涉及大量检查或使用临时值。
一个示例查找函数如下所示:
def lookup(data):
object_1 = data.get("object_1")
if object_1 is None:
# return your default
object_2 = object_1.get('object_2')
# and so on...
在 Python 3.10 及更高版本中,还有结构模式匹配可以提供帮助,在这种情况下,您可以这样做:
match data:
case {'object_1': {'object_2': {'list': [{'property': x}]}}}:
print(x) # should print 'hello'
case _:
print(<your_default>)
请记住,这仅适用于最新版本的 Python(Python.org 上的在线 Python 控制台仍仅适用于 Python3.9,代码以上会导致语法错误)。
在下面的代码中,如果 'object_1'/'object_2'/'list' 键不存在,x 将 return None。
此外,如果我们能够访问 'list' 键,那么我们的 x 不是 None 并且我们应该确保列表的长度应该大于零,然后我们可以搜索对于 'property' 键。
x = data.get('object_1', {}).get('object_2', {}).get('list')
if x is not None and len(x) > 0:
print(x[0].get('property'))
else:
print(None)
是否有一种无异常的方式来访问包含列表的字典中的值。例如,如果我有:
data = {
"object_1": {
"object_2": {
"list": [
{
"property": "hello"
}
]
}
}
}
如何安全地访问路径 data['object_1']['object_2']['list'][0]['property']
(即 return 如果无法在不抛出错误的情况下访问某些默认值)?我试图避免将它们包装在 try-except
中。我看过基于 reduce 的方法,但它没有考虑到字典中的列表。
在 JS 中,我可以这样写:
data.object_1?.object_2?.list[0]?.property ?? 'nothing_found'
Python中有类似的东西吗?
对于dict
你可以使用get
方法。对于列表,您可以注意索引:
data.get('object_1', {}).get('object_2', {}).get('list', [{}])[0].get('property', default)
这有点尴尬,因为它会为每次调用创建一个新的临时命令或丢失 get
。对于没有等效方法的列表也不是超级安全。
您也可以将 getter 包装在一个小例程中以支持列表,但这并不值得。您最好编写一个 one-off 实用函数,该函数使用异常处理或初步检查来处理您想要响应的情况:
def get(obj, *keys, default=None):
for key in keys:
try:
obj = obj[key]
except KeyError, IndexError:
return default
return obj
异常处理与其他方式相比有几个巨大的优势。一方面,您不必根据对象是字典还是列表对键进行单独检查。另一方面,您可以支持几乎任何其他支持 __getitem__
索引的合理类型。为了表明我的意思,这里是请求许可而不是宽恕的方法:
from collections.abc import Mapping, Sequence
from operator import index
def get(obj, *keys, default=None):
for key in keys:
if isinstance(obj, Mapping):
if key not in obj:
return default
elif isinstance(obj, Sequence):
try:
idx = index(key)
except TypeError:
return default
if len(obj) <= idx or len(obj) < -idx:
return default
obj = obj[key]
return obj
观察检查是多么尴尬和 error-prone。尝试传入一个自定义对象而不是 list
,或者一个不是整数的键。在 Python 中,小心使用异常是你的朋友,请求宽恕而不是许可是 pythonic 的原因是有原因的。
呃。是的,访问这样的 JSON 数据结构真是太糟糕了, 有点尴尬。
Glom 救援!
有两种获胜方式:
您可以只指定
... , default=None)
以避免异常,..或..使用
Coalesce
。print(glom(data, {'object_1.object_2.list': ['property']}, default=None))
有一种方法可以做到这一点,但它会涉及 get
方法,并且会涉及大量检查或使用临时值。
一个示例查找函数如下所示:
def lookup(data):
object_1 = data.get("object_1")
if object_1 is None:
# return your default
object_2 = object_1.get('object_2')
# and so on...
在 Python 3.10 及更高版本中,还有结构模式匹配可以提供帮助,在这种情况下,您可以这样做:
match data:
case {'object_1': {'object_2': {'list': [{'property': x}]}}}:
print(x) # should print 'hello'
case _:
print(<your_default>)
请记住,这仅适用于最新版本的 Python(Python.org 上的在线 Python 控制台仍仅适用于 Python3.9,代码以上会导致语法错误)。
在下面的代码中,如果 'object_1'/'object_2'/'list' 键不存在,x 将 return None。
此外,如果我们能够访问 'list' 键,那么我们的 x 不是 None 并且我们应该确保列表的长度应该大于零,然后我们可以搜索对于 'property' 键。
x = data.get('object_1', {}).get('object_2', {}).get('list')
if x is not None and len(x) > 0:
print(x[0].get('property'))
else:
print(None)