如何使用点"." 访问字典成员?

bod*_*ydo 230 python syntax dictionary nested

如何通过点"."访问Python字典成员?

例如,mydict['val']我不想写作,而是写作mydict.val.

此外,我想以这种方式访问​​嵌套的dicts.例如

mydict.mydict2.val 
Run Code Online (Sandbox Code Playgroud)

会参考

mydict = { 'mydict2': { 'val': ... } }
Run Code Online (Sandbox Code Playgroud)

der*_*k73 219

我一直把它保存在一个util文件中.您也可以在自己的课程中使用它作为mixin.

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'
Run Code Online (Sandbox Code Playgroud)

  • @tmthyjames你可以简单地在getter方法中返回dotdict类型对象以递归方式访问带点符号的属性,如:```python class DotDict(dict):"""dot.notation访问字典属性"""def __getattr __(*args ):val = dict.get(*args)如果type(val)是dict,则返回DotDict(val),否则val __setattr__ = dict .__ setitem__ __delattr__ = dict .__ delitem__``` (13认同)
  • +1表示简单.但似乎不适用于嵌套的dicts.`d = {'foo':{'bar':'baz'}}; d = dotdict(d); d.foo.bar`抛出一个属性错误,但``d.foo`工作正常. (7认同)
  • 非常简单的答案,太棒了!你碰巧知道我需要做什么才能在IPython工作中完成制表工作吗?该类需要实现__dir __(self),但不知怎的,我无法让它工作. (4认同)
  • 为什么你使用“dict.get”而不是“dict.__getitem__”? (3认同)
  • 经过实验,`get`的确是个坏主意,因为它会返回`None`而不是因为缺少项目而引发错误... (3认同)
  • 是的,这不适用于复杂的嵌套结构. (2认同)
  • @tmthyjames,另一种允许嵌套的方法:https://gist.github.com/miku/dc6d06ed894bc23dfd5a364b7def5ed8 (2认同)

epo*_*ool 127

你可以使用我刚刚创建的这个类来完成它.使用此类,您可以Map像使用另一个字典(包括json序列化)或使用点表示法一样使用该对象.我希望能帮助你:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]
Run Code Online (Sandbox Code Playgroud)

用法示例:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']
Run Code Online (Sandbox Code Playgroud)

  • 为了处理Python 3,我将`.iteritems()`更新为`.items()` (16认同)
  • 请注意,这将与普通期望的行为不同,因为如果该属性不存在,它将不会引发"AttributeError".相反,它会返回`None`. (9认同)
  • 您可以将构造函数简化为`self.update(*args,**kwargs)`.另外,你可以添加`__missing __(self,key):value = self [key] = type(self)(); 返回值`.然后,您可以使用点表示法添加缺少的条目.如果你想要它是可选择的,你可以添加`__getstate__`和`__setstate__` (4认同)

Chr*_*ord 100

dotmap通过安装pip

pip install dotmap
Run Code Online (Sandbox Code Playgroud)

它完成了你想要它做的一切和子类dict,所以它像普通的字典一样运行:

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'
Run Code Online (Sandbox Code Playgroud)

最重要的是,您可以将它转换为dict对象:

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor
Run Code Online (Sandbox Code Playgroud)

这意味着如果您要访问的内容已经在dict表单中,您可以将其转换DotMap为便于访问:

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city
Run Code Online (Sandbox Code Playgroud)

最后,它会自动创建新的子DotMap实例,以便您可以执行以下操作:

m = DotMap()
m.people.steve.age = 31
Run Code Online (Sandbox Code Playgroud)

与束的比较

完全披露:我是DotMap的创建者.我创建它因为Bunch缺少这些功能

  • 记住订单项是按顺序添加和迭代的
  • 自动子项DotMap创建,当您拥有大量层次结构时,可以节省时间并使代码更清晰
  • 从a构造dict并递归地将所有子dict实例转换为DotMap

  • :-) 您可以使用名称中已经包含点的键吗?`{"test.foo": "bar"}` 可以通过 `mymap.test.foo` 访问 那太棒了。将平面地图转换为深度地图需要一些回归,然后将 DotMap 应用于它,但这是值得的! (3认同)

Kug*_*gel 56

从dict派生并实现__getattr____setattr__.

或者你可以使用非常相似的.

我不认为monkeypatch内置的dict类是可能的.

  • 正确.你不能monkeypatch`dict`(感谢上帝). (24认同)
  • Monkeypatching使用Python(或任何语言)的动态性来改变通常在源代码中定义的东西.它特别适用于在创建类之后更改类的定义. (6认同)
  • 猴子补丁到底是什么意思?我听说过但没用过。(很抱歉,我问这样的新手问题,我编程方面还不太好(我才是二年级学生。) (2认同)

Dmi*_*kov 27

使用SimpleNamespace

>>> from types import SimpleNamespace   
>>> d = dict(x=[1, 2], y=['a', 'b'])
>>> ns = SimpleNamespace(**d)
>>> ns.x
[1, 2]
>>> ns
namespace(x=[1, 2], y=['a', 'b'])
Run Code Online (Sandbox Code Playgroud)

  • 不支持嵌套Dict。https://docs.python.org/3.3/library/types.html#types.SimpleNamespace (4认同)
  • 这是否解释了嵌套字典? (3认同)
  • 这种方法效果更好。(从文件加载json) (2认同)

tdi*_*ihp 18

我试过这个:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]
Run Code Online (Sandbox Code Playgroud)

你也可以试试__getattribute__.

使每个dict成为一种dotdict就足够了,如果你想从多层dict中初始化它,也可以尝试实现__init__.


Dav*_*ave 17

Fabric有一个非常好的,最小的实现.扩展它以允许嵌套访问,我们可以使用a defaultdict,结果看起来像这样:

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

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

    def __setattr__(self, key, value):
        self[key] = value
Run Code Online (Sandbox Code Playgroud)

按如下方式使用它:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234
Run Code Online (Sandbox Code Playgroud)

这详细阐述了库格尔的"从字典中__getattr____setattr__得出并实施"的回答.现在你知道了!

  • 很高兴包含一个默认字典 - 但这似乎只在从头开始开始字典时才有效。如果我们需要递归地将现有字典转换为“dotdict”。这是一个替代的“dotdict”,它允许递归地转换现有的“dict”对象:https://gist.github.com/miku/dc6d06ed894bc23dfd5a364b7def5ed8#file-23689767-py (3认同)

Pra*_*pta 15

I recently came across the 'Box' library which does the same thing.

Installation command : pip install python-box

Example:

from box import Box

mydict = {"key1":{"v1":0.375,
                    "v2":0.625},
          "key2":0.125,
          }
mydict = Box(mydict)

print(mydict.key1.v1)
Run Code Online (Sandbox Code Playgroud)

I found it to be more effective than other existing libraries like dotmap, which generate python recursion error when you have large nested dicts.

link to library and details: https://pypi.org/project/python-box/


小智 15

您可以使用 SimpleNamespace 来实现这一点

from types import SimpleNamespace
# Assign values
args = SimpleNamespace()
args.username = 'admin'

# Retrive values
print(args.username)  # output: admin
Run Code Online (Sandbox Code Playgroud)

  • 重复 Dmitry Zotikov 之前的回答 /sf/answers/4163652111/ (3认同)

Mik*_*ham 9

别.属性访问和索引是Python中的独立事物,您不应该希望它们执行相同的操作.namedtuple如果你有一些应该具有可访问属性的东西并使用[]符号从dict中获取一个项目,那么创建一个类(可能由一个类创建).

  • 如果它对JavaScript来说足够好,为什么不用Python呢? (27认同)
  • 你已经知道了很好的Python风格:我们告诉你,不要假装dict的值是属性.这是不好的做法.例如,如果要存储与dict的现有属性同名的值,例如"items"或"get"或"pop",该怎么办?可能令人困惑的事情.所以不要这样做! (9认同)
  • 哎呀,我忘记了'items','get'或'pop等属性.感谢您提出这个重要的例子! (5认同)
  • @Gabe,已经很久了......但我认为值得一提.它在JS中并不"足够好":它在JS中"足够糟糕".当你存储与原型链中其他重要属性同名的keys/attr时会很有趣. (5认同)
  • 我不同意这里做出的相当教条的声明。虽然这通常是正确的,但 . 符号更加清晰易读。我可以看到很多用例,其中引起问题的可能性非常小。 (3认同)
  • 我可以看到一个用例;实际上,我是在几周前完成的。就我而言,我想要一个可以使用点表示法访问属性的对象。我发现简单地从dict继承非常容易,因此我获得了所有dict内置的功能,但是此对象的公共接口使用点符号(本质上是一些静态数据的只读接口)。我的用户使用'foo.bar'比使用'foo [“ bar”]'更快乐,并且我很高兴可以支持dict数据类型的功能。 (2认同)

vol*_*myr 9

如果你想修改你修改过的字典,你需要在上面的答案中添加一些状态方法:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self
Run Code Online (Sandbox Code Playgroud)


pba*_*nka 6

语言本身不支持这一点,但有时这仍然是一个有用的要求。除了 Bunch 配方之外,您还可以编写一个小方法,可以使用点字符串访问字典:

def get_var(input_dict, accessor_string):
    """Gets data from a dictionary using a dotted accessor-string"""
    current_data = input_dict
    for chunk in accessor_string.split('.'):
        current_data = current_data.get(chunk, {})
    return current_data
Run Code Online (Sandbox Code Playgroud)

这将支持这样的事情:

>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}}
>> output = get_var(test_dict, 'thing.spam.foo.cheeze')
>> print output
'bar'
>>
Run Code Online (Sandbox Code Playgroud)


M J*_*M J 6

在Kugel的回答的基础上,考虑到Mike Graham的谨慎言辞,如果我们制作一个包装器怎么办?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setattr__(self, name, value):
    self._data[name] = value  

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other
Run Code Online (Sandbox Code Playgroud)


tou*_*ody 6

为了建立在 epool 的回答之上,这个版本允许你通过点运算符访问任何内部的字典:

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}
Run Code Online (Sandbox Code Playgroud)

例如,foo.bar.baz[1].baba返回"loo"

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.items():
                    if isinstance(v, dict):
                        v = Map(v)
                    if isinstance(v, list):
                        self.__convert(v)
                    self[k] = v

        if kwargs:
            for k, v in kwargs.items():
                if isinstance(v, dict):
                    v = Map(v)
                elif isinstance(v, list):
                    self.__convert(v)
                self[k] = v

    def __convert(self, v):
        for elem in range(0, len(v)):
            if isinstance(v[elem], dict):
                v[elem] = Map(v[elem])
            elif isinstance(v[elem], list):
                self.__convert(v[elem])

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]
Run Code Online (Sandbox Code Playgroud)

  • Python 3:用“items()”替换“iteritems()”,用“range()”替换“xrange()” (2认同)

rv.*_*tch 6

我不喜欢在(超过)10 年的火灾中添加另一根木头,但我也会查看dotwiz我最近发布的库 - 实际上就在今年。

\n

这是一个相对较小的库,在基准测试中的获取(访问)和设置(创建)时间方面也表现得非常好,至少与其他替代方案相比是这样。

\n

安装dotwiz通过pip

\n
pip install dotwiz\n
Run Code Online (Sandbox Code Playgroud)\n

它可以完成您想要它做的所有事情并进行子类化dict,因此它的操作就像普通的字典一样:

\n
from dotwiz import DotWiz\n\ndw = DotWiz()\ndw.hello = \'world\'\ndw.hello\ndw.hello += \'!\'\n# dw.hello and dw[\'hello\'] now both return \'world!\'\ndw.val = 5\ndw.val2 = \'Sam\'\n
Run Code Online (Sandbox Code Playgroud)\n

最重要的是,您可以将其与dict对象相互转换:

\n
d = dw.to_dict()\ndw = DotWiz(d) # automatic conversion in constructor\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着,如果您想要访问的内容已经在dict表单中,您可以将其转换为DotWiz以便于访问:

\n
import json\njson_dict = json.loads(text)\ndata = DotWiz(json_dict)\nprint data.location.city\n
Run Code Online (Sandbox Code Playgroud)\n

最后,我正在处理的一些令人兴奋的事情是现有的功能请求,以便它自动创建新的子DotWiz实例,以便您可以执行以下操作:

\n
dw = DotWiz()\ndw[\'people.steve.age\'] = 31\n\ndw\n# \xe2\x9c\xab(people=\xe2\x9c\xab(steve=\xe2\x9c\xab(age=31)))\n
Run Code Online (Sandbox Code Playgroud)\n

与比较dotmap

\n

我在下面添加了一个快速而肮脏的性能比较dotmap

\n

首先,使用以下命令安装两个库pip

\n
pip install dotwiz dotmap\n
Run Code Online (Sandbox Code Playgroud)\n

我出于基准目的想出了以下代码:

\n
pip install dotwiz\n
Run Code Online (Sandbox Code Playgroud)\n

结果,在我的 M1 Mac 上运行 Python 3.10:

\n
dotwiz (create):   0.189\ndotmap (create):   1.085\ndotwiz (get):   0.014\ndotmap (get):   0.335\n
Run Code Online (Sandbox Code Playgroud)\n


Sen*_*hil 5

我喜欢Munch,它在点访问的基础上提供了许多方便的选择。

进口午餐

temp_1 = {'person':{'fname':'senthil','lname':'ramalingam'}}

dict_munch = munch.munchify(temp_1)

dict_munch.person.fname


IRS*_*HAD 5

使用__getattr__非常简单,可在Python 3.4.3中使用

class myDict(dict):
    def __getattr__(self,val):
        return self[val]


blockBody=myDict()
blockBody['item1']=10000
blockBody['item2']="StackOverflow"
print(blockBody.item1)
print(blockBody.item2)
Run Code Online (Sandbox Code Playgroud)

输出:

10000
StackOverflow
Run Code Online (Sandbox Code Playgroud)