如何在python中使用dict的点符号?

bat*_*man 53 python dictionary nested

我是python的新手,我希望我能用.符号来访问a的值dict.

让我们说我test喜欢这样:

>>> test = dict()
>>> test['name'] = 'value'
>>> print(test['name'])
value
Run Code Online (Sandbox Code Playgroud)

但是,我希望我能做到test.namevalue.事实上,我通过覆盖__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')
Run Code Online (Sandbox Code Playgroud)

这很有效!当我做:

test.name // I get value.
Run Code Online (Sandbox Code Playgroud)

但问题是当我test单独打印时,我得到的错误是:

'Sorry no key matches'
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

wim*_*wim 92

此功能已存在于标准库中,因此我建议您只使用他们的类.

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

通过常规属性访问可以实现添加,修改和删除值,即您可以使用n.key = val和等语句del n.key.

再次回到dict:

>>> vars(n)
{'key1': 'value1', 'key2': 'value2'}
Run Code Online (Sandbox Code Playgroud)

dict中的键应该是字符串标识符,以便属性访问正常工作.

Python 3.3中添加了简单的命名空间.对于该语言的旧版本,argparse.Namespace具有类似的行为.

  • 请注意,当“d”是一个字典时“d”中的“key”有效,但当“d”是“SimpleNamespace”时则不起作用 (4认同)
  • [Fabric](http://www.fabfile.org)也有一个不错的最小[实现](https://github.com/fabric/fabric/blob/1.13.1/fabric/utils.py#L186),我还在[此处](http://stackoverflow.com/a/41274937/307614)发布了该信息。 (2认同)
  • 如果可以递归的话,那就太好了。即访问`myobj.subdict.subdict`。 (2认同)
  • @Pithikos 有一个提供该功能的第三方库,请查看 [python-box](https://pypi.python.org/pypi/python-box/)。 (2认同)

for*_*ran 31

我假设您对Javascript感到满意,并希望借用这种语法......我可以通过个人经验告诉您这不是一个好主意.

它确实看起来不那么冗长和整洁; 但从长远来看,它只是模糊不清.Dicts是dicts,并试图让它们表现得像具有属性的对象可能会导致(坏)惊喜.

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

但通过阅读你的例子,似乎你正在尝试不同的东西......因为点运算符已经在__dict__没有任何额外代码的情况下查看属性.

  • 一个糟糕的惊喜示例:如果你在dict中有一个恰好是python关键字的键,例如字符串''for',则属性访问失败,并且没有优雅的方法来正确处理这种情况.整个想法从根本上打破了. (6认同)
  • @QianChen JavaScript _可以_很优雅,也可以很混乱(就像大多数语言一样)。尝试像使用 JavaScript(或任何其他两种语言)一样使用 Python 肯定会造成混乱。如果用某种语言有一种预期的方式来做某事,那么偏离这种方式只会带来痛苦。 (3认同)
  • 另一方面,自动完成功能使代码更高效,更不易出错。如果可以预定义dict结构,那将很完美。* (2认同)
  • JavaScript 很优雅。 (2认同)

Mic*_* H. 10

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

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
Run Code Online (Sandbox Code Playgroud)

请注意,这不支持位于例如列表中的字典的点符号。


小智 7

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)
Run Code Online (Sandbox Code Playgroud)


bru*_*ers 6

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

附带说明:不要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)
Run Code Online (Sandbox Code Playgroud)

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


Yan*_*ann 5

您可以使用一个命名的元组吗?

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)
Run Code Online (Sandbox Code Playgroud)

  • 这是一种通过点分表示法访问数据结构的有趣方式,但它似乎与JSON或dict并不特别兼容。在确实提供JSON和dict支持的幕后,有一些库使用命名元组。尝试https://github.com/dsc/bunch或https://github.com/kennknowles/python-jsonpath-rw (2认同)

sec*_*ilm 5

您可以使用内置方法argparse.Namespace()

import argparse

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

print(args.name)
# 'value'
Run Code Online (Sandbox Code Playgroud)

您还可以通过获取原始字典vars(args)


小智 -1

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

print text
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然这在技术上可以解决问题中提到的具体情况,但破坏内置行为来修补其他内置行为的黑客在客观上是糟糕的代码。 (2认同)