我如何使Python字典成员访问通过点“。”?

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

我还想以这种方式访问嵌套字典。例如

mydict.mydict2.val 

会提到

mydict = { 'mydict2': { 'val': ... } }

当前回答

我试了一下:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]

你也可以尝试__getattribute__。

使每个字典都是一种类型的dotdict就足够了,如果你想从多层字典初始化它,也可以尝试实现__init__。

其他回答

可以使用dotsi来支持完整列表、dict和递归,并使用一些扩展方法

pip install dotsi

and

>>> import dotsi
>>> 
>>> d = dotsi.Dict({"foo": {"bar": "baz"}})     # Basic
>>> d.foo.bar
'baz'
>>> d.users = [{"id": 0, "name": "Alice"}]   # List
>>> d.users[0].name
'Alice'
>>> d.users.append({"id": 1, "name": "Becca"}); # Append
>>> d.users[1].name
'Becca'
>>> d.users += [{"id": 2, "name": "Cathy"}];    # `+=`
>>> d.users[2].name
'Cathy'
>>> d.update({"tasks": [{"id": "a", "text": "Task A"}]});
>>> d.tasks[0].text
'Task A'
>>> d.tasks[0].tags = ["red", "white", "blue"];
>>> d.tasks[0].tags[2];
'blue'
>>> d.tasks[0].pop("tags")                      # `.pop()`
['red', 'white', 'blue']
>>> 
>>> import pprint
>>> pprint.pprint(d)
{'foo': {'bar': 'baz'},
 'tasks': [{'id': 'a', 'text': 'Task A'}],
 'users': [{'id': 0, 'name': 'Alice'},
           {'id': 1, 'name': 'Becca'},
           {'id': 2, 'name': 'Cathy'}]}
>>> 
>>> type(d.users)       # dotsi.Dict (AKA dotsi.DotsiDict)
<class 'dotsi.DotsiList'>
>>> type(d.users[0])    # dotsi.List (AKA dotsi.DotsiList)
<class 'dotsi.DotsiDict'> 
>>> 

获得点访问(但不是数组访问)的一个简单方法是在Python中使用一个普通对象。是这样的:

class YourObject:
    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

...像这样使用它:

>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"

... 把它转换成字典:

>>> print(obj.__dict__)
{"key": "value"}

kaggle_environments使用的实现是一个名为structify的函数。

class Struct(dict):
    def __init__(self, **entries):
        entries = {k: v for k, v in entries.items() if k != "items"}
        dict.__init__(self, entries)
        self.__dict__.update(entries)

    def __setattr__(self, attr, value):
        self.__dict__[attr] = value
        self[attr] = value

# Added benefit of cloning lists and dicts.
def structify(o):
    if isinstance(o, list):
        return [structify(o[i]) for i in range(len(o))]
    elif isinstance(o, dict):
        return Struct(**{k: structify(v) for k, v in o.items()})
    return o

https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/utils.py

这可能有助于在《ConnectX》等游戏中测试AI模拟代理

from kaggle_environments import structify

obs  = structify({ 'remainingOverageTime': 60, 'step': 0, 'mark': 1, 'board': [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]})
conf = structify({ 'timeout': 2, 'actTimeout': 2, 'agentTimeout': 60, 'episodeSteps': 1000, 'runTimeout': 1200, 'columns': 7, 'rows': 6, 'inarow': 4, '__raw_path__': '/kaggle_simulations/agent/main.py' })

def agent(obs, conf):
  action = obs.step % conf.columns
  return action

一个很微妙的解

class DotDict(dict):

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, key):

        def typer(candidate):
            if isinstance(candidate, dict):
                return DotDict(candidate)

            if isinstance(candidate, str):  # iterable but no need to iter
                return candidate

            try:  # other iterable are processed as list
                return [typer(item) for item in candidate]
            except TypeError:
                return candidate

            return candidate

        return typer(dict.get(self, key))

我的观点:出于我自己的目的,我开发了minydra,一个简单的命令行解析器,包括一个自定义类MinyDict(灵感来自addict):


In [1]: from minydra import MinyDict

In [2]: args = MinyDict({"foo": "bar", "yes.no.maybe": "idontknow"}).pretty_print(); args
╭──────────────────────────────╮
│ foo          : bar           │
│ yes.no.maybe : idontknow     │
╰──────────────────────────────╯
Out[2]: {'foo': 'bar', 'yes.no.maybe': 'idontknow'}

In [3]: args.resolve().pretty_print(); args
╭──────────────────────────╮
│ foo : bar                │
│ yes                      │
│ │no                      │
│ │ │maybe : idontknow     │
╰──────────────────────────╯
Out[3]: {'foo': 'bar', 'yes': {'no': {'maybe': 'idontknow'}}}

In [4]: args.yes.no.maybe
Out[4]: "idontknow"

In [5]: "foo" in args
Out[5]: True

In [6]: "rick" in args
Out[6]: False

In [7]: args.morty is None
Out[7]: True

In [8]: args.items()
Out[8]: dict_items([('foo', 'bar'), ('yes', {'no': {'maybe': 'idontknow'}})])

它通过向json yaml和pickle添加转储/加载方法来上瘾,并且在MinyDict.update()中也有一个严格的模式来防止创建新键(这对于防止命令行中的错字很有用)