Python:列表的安全词典访问?

发布于 2025-01-21 18:00:25 字数 643 浏览 3 评论 0原文

是否有一种例外的免费方法,可以从包含列表的字典中访问值。例如,如果我有:

data = {
    "object_1": {
        "object_2": {
            "list": [
                {
                    "property": "hello"
                }
            ]
        }
    }
}

如何访问路径data ['object_1'] ['object_2'] ['list'] [0] [0] ['property']安全(即返回一些默认值值如果不可能而不丢失错误)?我正在尝试避免将它们包裹在try-except's中。我已经看到基于基于的方法,但它没有考虑到字典中的列表。

在JS中,我可以写一些类似的内容:

data.object_1?.object_2?.list[0]?.property ?? 'nothing_found'

python中有类似的东西吗?

Is there an exception free way to access values from a dictionary containing lists. For example, if I have:

data = {
    "object_1": {
        "object_2": {
            "list": [
                {
                    "property": "hello"
                }
            ]
        }
    }
}

How do I access the path data['object_1']['object_2']['list'][0]['property'] safely(i.e. return some default value if not possible to access without throwing error)? I am trying to avoid wrapping these in try-except's. I have seen the reduce based approach but it doesn't take into account having lists inside the dictionary.

In JS, I can write something like:

data.object_1?.object_2?.list[0]?.property ?? 'nothing_found'

Is there something similar in Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无人问我粥可暖 2025-01-28 18:00:25

对于dict,您可以使用get方法。对于列表,您可以谨慎使用索引:

data.get('object_1', {}).get('object_2', {}).get('list', [{}])[0].get('property', default)

这有点尴尬,因为它会为每个呼叫get而制造新的临时命令或丢失。对于没有同等方法的列表,它也不是超级安全的。

您也可以将Getter包裹在一个小的例程中以支持列表,但这并不值得。您最好编写一个一次性的实用功能,该功能使用异常处理或初步检查来处理您要反应的案例:

def get(obj, *keys, default=None):
    for key in keys:
        try:
            obj = obj[key]
        except KeyError, IndexError:
            return default
    return obj

Exception Handsing与以其他方式相比具有几个巨大的优势。一方面,您不必根据对象是dict还是列表对密钥进行单独检查。另一方面,您几乎可以支持支持__ 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

观察检查的尴尬和错误。尝试传递自定义对象,而不是list或不是整数的密钥。在Python中,您的朋友精心使用的例外是,有原因是要求寻求宽恕而不是允许的原因。

For dict you can use the get method. For lists you can just be careful with the index:

data.get('object_1', {}).get('object_2', {}).get('list', [{}])[0].get('property', default)

This is a bit awkward because it makes a new temporary dict or lost for each call get. It's also not super safe for lists, which don't have an equivalent method.

You can wrap the getter in a small routine to support lists too, but it's not really worth it. You're better off writing a one-off utility function that uses either exception handling or preliminary checking to handle the cases you want to react to:

def get(obj, *keys, default=None):
    for key in keys:
        try:
            obj = obj[key]
        except KeyError, IndexError:
            return default
    return obj

Exception handing has a couple of huge advantages over doing it the other way. For one thing, you don't have to do separate checks on the key depending on whether the object is a dict or list. For another, you can support almost any other reasonable type that supports __getitem__ indexing. To show what I mean, here is the asking for permission rather than forgiveness approach:

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

Observe how awkward and error-prone the checking is. Try passing in a custom object instead of a list, or a key that's not an integer. In Python, carefully used exceptions are your friend, and there's a reason it's pythonic to ask for forgiveness rather than for permission.

糖粟与秋泊 2025-01-28 18:00:25

UGGH。是的,访问此类JSON数据结构很糟糕,
有点尴尬。

glom 进行救援!

有两种获胜的方法:

  1. 您可以只指定...,默认= none)避免异常,..

  2. 例外/PI.html#defaults-with-coalesce“ rel =“ nofollow noreferrer”> cocecce

      print(glom(data,{'object_1.object_2.list':['属性']},默认值= none))
     

Uggh. Yeah, accessing such JSON data structures is just terrible,
it's a bit awkward.

Glom to the rescue!

There's two ways to win:

  1. You can just specify ... , default=None) to avoid exceptions, ..or..

  2. Use Coalesce.

     print(glom(data, {'object_1.object_2.list': ['property']}, default=None))
    
待天淡蓝洁白时 2025-01-28 18:00:25

在以下代码中,如果“ object_1'/'object_2'/'list”键不存在,则x将不返回。

另外,如果我们能够访问“列表”键,那么我们没有X,因为没有X,我们应该确保列表的长度应大于零,然后我们可以搜索“属性”键。

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)

In the below code, x will return None if 'object_1'/'object_2'/'list' key does not exist.

Also, if we are able to access 'list' key then we have x as Not None and we should ensure that the length of the list should be greater than zero and then we can search for 'property' key.

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)
独闯女儿国 2025-01-28 18:00:25

有一种方法可以做到这一点,但它涉及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上,上面的代码将导致语法错误)。

There is one way to do that, but it would involve the get method and would involve a lot of checking, or using temporary values.

One example lookup function would look like that:

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...

In Python 3.10 and above, there is also structural pattern matching that can help, in which case you would do something like this:

match data:
    case {'object_1': {'object_2': {'list': [{'property': x}]}}}:
        print(x) # should print 'hello'
    case _:
        print(<your_default>)

Please remember that this only works with the latest versions of Python (the online Python console on Python.org is still only on Python3.9, and the code above would cause a syntax error).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文