如何在 python 中使用点符号来表示 dict?

我对 python 非常陌生,我希望我可以使用 .表示法来访问 dict的值。

假设我有这样的 test:

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

但我希望我能做 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'

为什么会这样?

127981 次浏览

向类中添加 __repr__()方法,以便可以自定义要显示的文本

print text

点击这里了解更多: https://web.archive.org/web/20121022015531/http://diveintopython.net/object_oriented_framework/special_class_methods2.html

我假设你对 Javascript 很熟悉,并且想借用这种语法... ... 根据个人经验,我可以告诉你这不是一个好主意。

它确实看起来不那么冗长和整洁; 但从长远来看,它只是模糊不清。Dicts 就是 Dicts,试图让它们表现得像带有属性的对象可能会导致(糟糕的)意外。

如果您需要操作对象的字段,就像操作字典一样,那么您总是可以在需要时使用内部 __dict__属性,然后就可以使用 明确地清楚地了解您正在做什么。或者也可以使用 getattr(obj, 'key')来考虑继承结构和类属性。

但是通过阅读您的示例,似乎您正在尝试一些不同的东西... ... 因为点运算符将已经在 __dict__属性中查找,而不需要任何额外的代码。

你能用 叫 Tuple?

from collections import namedtuple
Test = namedtuple('Test', 'name foo bar')
my_test = Test('value', 'foo_val', 'bar_val')
print(my_test)
print(my_test.name)

这个功能已经是 存在于标准库中了,所以我建议您使用它们的类。

>>> from types import SimpleNamespace
>>> d = {'key1': 'value1', 'key2': 'value2'}
>>> n = SimpleNamespace(**d)
>>> print(n)
namespace(key1='value1', key2='value2')
>>> n.key2
'value2'

添加、修改和删除值是通过常规属性访问实现的,也就是说,您可以使用诸如 n.key = valdel n.key之类的语句。

再回到一个结论:

>>> vars(n)
{'key1': 'value1', 'key2': 'value2'}

在您的字典中的关键字应该是字符串 识别资料属性访问正常工作。

在 Python 3.3中添加了简单的名称空间。

使用 __getattr__时必须小心,因为它用于许多内置的 Python 功能。

试试这样..。

class JuspayObject:


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


def __getattr__(self, key):
# First, try to return from _response
try:
return self.__dict__['_response'][key]
except KeyError:
pass
# If that fails, return default behavior so we don't break Python
try:
return self.__dict__[key]
except KeyError:
raise AttributeError, key


>>> j = JuspayObject({'foo': 'bar'})
>>> j.foo
'bar'
>>> j
<__main__.JuspayObject instance at 0x7fbdd55965f0>

当所有其他属性查找规则失败时,将使用 __getattr__作为备份。当您尝试“打印”对象时,Python 会寻找一个 __repr__方法,由于您没有在类中实现它,因此它最终会调用 __getattr__(是的,在 Python 方法中也有属性)。您不应该假定使用哪个键 快点来调用,最重要的是,如果 __getattr__不能解析 key,它必须引发 AttributeError。

作为附注: 不要使用 self.__dict__访问普通属性,只要使用普通属性表示法:

class JuspayObject:


def __init__(self,response):
# don't use self.__dict__ here
self._response = response


def __getattr__(self,key):
try:
return self._response[key]
except KeyError,err:
raise AttributeError(key)

现在,如果您的类没有其他责任(Python 版本 > = 2.6,您不需要支持旧版本) ,您可以使用 namedtuple: http://docs.python.org/2/library/collections.html#collections.namedtuple

除了 这个答案之外,还可以添加对嵌套字典的支持:

from types import SimpleNamespace


class NestedNamespace(SimpleNamespace):
def __init__(self, dictionary, **kwargs):
super().__init__(**kwargs)
for key, value in dictionary.items():
if isinstance(value, dict):
self.__setattr__(key, NestedNamespace(value))
else:
self.__setattr__(key, value)


nested_namespace = NestedNamespace({
'parent': {
'child': {
'grandchild': 'value'
}
},
'normal_key': 'normal value',
})




print(nested_namespace.parent.child.grandchild)  # value
print(nested_namespace.normal_key)  # normal value

注意,这不支持位于 List 中的 dicts 的点符号。

你可以使用内置的方法 argparse.Namespace():

import argparse


args = argparse.Namespace()
args.name = 'value'


print(args.name)
# 'value'

你也可以通过 vars(args)获得原始的结果。

通过对 这个答案的一个小小的增加,你也可以支持列表:

class NestedNamespace(SimpleNamespace):
def __init__(self, dictionary, **kwargs):
super().__init__(**kwargs)
for key, value in dictionary.items():
if isinstance(value, dict):
self.__setattr__(key, NestedNamespace(value))
elif isinstance(value, list):
self.__setattr__(key, map(NestedNamespace, value))
else:
self.__setattr__(key, value)

我使用 dotted_dict软件包:

>>> from dotted_dict import DottedDict
>>> test = DottedDict()
>>> test.name = 'value'
>>> print(test.name)
value

下面是一个使用嵌套项的简单、方便的点符号助手示例:

def dict_get(data:dict, path:str, default = None):
pathList = re.split(r'\.', path, flags=re.IGNORECASE)
result = data
for key in pathList:
try:
key = int(key) if key.isnumeric() else key
result = result[key]
except:
result = default
break
    

return result

用法例子:

my_dict = {"test1": "str1", "nested_dict": {"test2": "str2"}, "nested_list": ["str3", {"test4": "str4"}]}
print(dict_get(my_dict, "test1"))
# str1
print(dict_get(my_dict, "nested_dict.test2"))
# str2
print(dict_get(my_dict, "nested_list.1.test4"))
# str4
#!/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}))

2022年的答案: 我已经创建了 dotwiz包——这是一个快速、小巧的库,在大多数情况下似乎都能很好地执行。

>>> from dotwiz import DotWiz
>>> test = DotWiz(hello='world')
>>> test.works = True
>>> test
✫(hello='world', works=True)
>>> test.hello
'world'
>>> assert test.works
class convert_to_dot_notation(dict):
"""
Access dictionary attributes via dot notation
"""


__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__




test = {"name": "value"}
data = convert_to_dot_notation(test)
print(data.name)

这个特性被融入了 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

这个 lib 对于配置来说很方便,它实际上是为以下目的而设计的:

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

可以通过向 Dicts 添加点符号来解决大部分问题,但是总是存在名称空间问题。比如说,这是干什么的?

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

当嵌套过于丑陋时,我使用 胡言乱语(它是 JS 的 loash 的 Python 端口)以不同的方式来处理这些事情。