如何在Python中使用点表示法访问字典?

156

我对Python非常陌生,希望能够使用.符号来访问dict中的值。

比如说我有类似这样的test

>>> test = dict()
>>> test['name'] = 'value'
>>> print(test['name'])
value

但是我希望我能够执行test.name来获取value。实际上,我通过在我的类中重写__getattr__方法来实现:

但我希望我能够执行test.name来获取value。实际上,我通过在我的类中覆盖__getattr__方法来实现这一点:

class JuspayObject:

    def __init__(self,response):
        self.__dict__['_response'] = response

    def __getattr__(self,key): 
        try:
            return self._response[key]
        except KeyError,err:
            sys.stderr.write('Sorry no key matches')

这很有效! 当我执行以下操作时:

test.name // I get value.

但问题是当我只打印test时,会出现以下错误:

'Sorry no key matches'
为什么会发生这种情况?

当您请求字典中不存在的属性时,需要调用超类__getattr__。 - David Heffernan
@DavidHeffernan 像 OP 的示例这样的旧式类甚至有超类吗? - Aya
@Aya 没有主意。如果没有的话,使用一个新的样式类。反正还有谁会使用旧的样式类呢? - David Heffernan
1
@DavidHeffernan 嗯,标准 Python 库中仍然有很多旧式类,例如 cgi.py - Aya
1
参见:https://dev59.com/dXE95IYBdhLWcg3wV8e_ - dreftymac
16个回答

1
2022年的回答:我创建了 dotwiz 软件包,这是一个快速、微小的库,在大多数情况下似乎表现得非常出色。
>>> from dotwiz import DotWiz
>>> test = DotWiz(hello='world')
>>> test.works = True
>>> test
✫(hello='world', works=True)
>>> test.hello
'world'
>>> assert test.works

1

这个功能已经内置在OmegaConf中:

from omegaconf import OmegaConf

your_dict = {"k" : "v", "list" : [1, {"a": "1", "b": "2", 3: "c"}]}
adot_dict = OmegaConf.create(your_dict)

print(adot_dict.k)
print(adot_dict.list)

安装步骤如下:

pip install omegaconf

这个库是用来处理配置文件的,非常方便:

from omegaconf import OmegaConf
cfg = OmegaConf.load('config.yml')
print(cfg.data_path)

1
我使用了 dotted_dict 包:
    >>> from dotted_dict import DottedDict
    >>> test = DottedDict()
    >>> test.name = 'value'
    >>> print(test.name)
    value

相较于SimpleNamespace的优势

(参见@win的答案。)DottedDict是一个实际的dict

>>> isinstance(test, dict)
True

这样可以检查成员资格,例如:
>>> 'name' in test
True

相比之下,对于SimpleNamespace,你需要使用类似于hasattr(test, 'name')这样不太可读的内容。

不要使用DotMap

我是通过艰难的方式发现这个问题的。如果你引用了一个不存在的成员,它会添加该成员而不是抛出错误。这可能会导致代码中难以发现的错误:

>>> from dotmap import DotMap
>>> dm = DotMap()
>>> 'a' in dm
False
>>> x = dm.a
>>> 'a' in dm
True

0
#!/usr/bin/env python3


import json
from sklearn.utils import Bunch
from collections.abc import MutableMapping


def dotted(inpt: MutableMapping,
           *args,
           **kwargs
           ) -> Bunch:
    """
    Enables recursive dot notation for ``dict``.
    """

    return json.loads(json.dumps(inpt),
                      object_hook=lambda x:
                      Bunch(**{**Bunch(), **x}))

请解释一下你的代码。 - Muhammad Mohsin Khan
目标是将函数或类传递到“json.loads”函数的“object_hook”参数中,以允许非递归“点表示法”。我在这里使用了“sklearn.utils.Bunch”,但是在此示例中,“types.SimpleNamespace” https://dev59.com/32Qo5IYBdhLWcg3wKcnH#16279578 也可能有效。 - Frankthetank

0

你可以通过添加点符号到字典中来实现大多数情况下的hack,但总会存在命名空间问题。比如,这个是做什么的?

x = DotDict()
x["values"] = 1989
print(x. values)

我使用pydash,它是JS的lodash的Python版本,当嵌套变得太丑陋时,可以用不同的方式完成这些事情。


-1

2
虽然这在技术上可以解决问题中提到的特定情况,但是通过修改内置行为来修补其他内置行为的黑客行为是客观上糟糕的代码。 - vdwees

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接