如何使用点“。”访问字典成员?

2024-12-24 08:56:00
admin
原创
93
摘要:问题描述:如何使 Python 字典成员可通过点“。”访问?例如,mydict['val']我不想写,而想写mydict.val。我也想通过这种方式访问​​嵌套的字典。例如mydict.mydict2.val 指的是mydict = { 'mydict2': { 'val': ... } } 解决方案 1:...

问题描述:

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

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

我也想通过这种方式访问​​嵌套的字典。例如

mydict.mydict2.val 

指的是

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

解决方案 1:

我一直把它保存在一个实用程序文件中。您也可以将它用作您自己的类的混合器。

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'

解决方案 2:

你可以使用我刚刚创建的这个类来实现。使用这个类,你可以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]

使用示例:

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']

解决方案 3:

dotmap通过安装pip

pip install dotmap

它可以完成您想要它做的所有事情并且是子类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'

最重要的是,你可以将其转换为对象或从dict对象转换:

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

这意味着如果您想要访问的东西已经存在,您可以将其转变为易于访问的dict形式:DotMap

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

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

m = DotMap()
m.people.steve.age = 31

与 Bunch 的比较

全面披露:我是DotMap的创建者。我之所以创建它,是因为Bunch它缺少这些功能

  • 记住添加项目的顺序并按该顺序进行迭代

  • 自动DotMap创建子项,这可以节省时间,并且在具有大量层次结构时可以使代码更简洁

  • 从 a 构造dict并递归地将所有子dict实例转换为DotMap

解决方案 4:

使用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'])

解决方案 5:

从字典和中得出并实现__getattr____setattr__

或者您可以使用非常相似的Bunch 。

我认为无法对内置的 dict 类进行 monkeypatch 。

解决方案 6:

Fabric有一个非常好的、极简的实现。扩展它以允许嵌套访问,我们可以使用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

使用方法如下:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

这稍微阐述了 Kugel 的回答“从 dict 和实现__getattr____setattr__” 。现在你知道怎么做了!

解决方案 7:

我尝试了这个:

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

你也可以尝试__getattribute__一下。

将每个字典都设为 dotdict 类型就足够了,如果你想从多层字典中初始化它,__init__也可以尝试实现。

解决方案 8:

我最近发现了可以做同样事情的“ Box ”库。

安装命令:pip install python-box

例子:

from box import Box

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

print(mydict.key1.v1)

我发现它比其他现有库(如 dotmap)更有效,当你有大量嵌套字典时会产生 python 递归错误。

库链接和详细信息:https://pypi.org/project/python-box/

解决方案 9:

不要。属性访问和索引在 Python 中是分开的,您不应该希望它们执行相同的操作。namedtuple如果您有某些东西应该具有可访问的属性,请创建一个类(可能是由 创建的类),并使用[]符号从字典中获取项目。

解决方案 10:

如果您想要腌制修改后的字典,则需要向上述答案添加一些状态方法:

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

解决方案 11:

您可以使用 SimpleNamespace 实现此目的

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

# Retrive values
print(args.username)  # output: admin

解决方案 12:

为了建立在 epool 的答案之上,此版本允许您通过点运算符访问里面的任何字典:

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}

例如,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]

解决方案 13:

基于库格尔的回答并考虑到迈克·格雷厄姆的警告,如果我们制作一个包装纸会怎么样?

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

解决方案 14:

使用__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)

输出:

10000
StackOverflow

解决方案 15:

我喜欢Munch,它除了点访问之外还提供了很多方便的选项。

进口 munch

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

dict_munch = munch.munchify(temp_1)

dict_munch.person.fname

解决方案 16:

我不喜欢在(超过) 10 年的火堆里再添加一根木头,但我也会查看dotwiz我最近发布的图书馆 - 实际上就是今年。

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

dotwiz通过安装pip

pip install dotwiz

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

from dotwiz import DotWiz

dw = DotWiz()
dw.hello = 'world'
dw.hello
dw.hello += '!'
# dw.hello and dw['hello'] now both return 'world!'
dw.val = 5
dw.val2 = 'Sam'

最重要的是,你可以将其转换为对象或从dict对象转换:

d = dw.to_dict()
dw = DotWiz(d) # automatic conversion in constructor

这意味着如果您想要访问的东西已经存在,您可以将其转变为易于访问的dict形式:DotWiz

import json
json_dict = json.loads(text)
data = DotWiz(json_dict)
print data.location.city

最后,我正在研究的一件令人兴奋的事情是一个现有的功能请求,以便它自动创建新的子DotWiz实例,这样您就可以执行如下操作:

dw = DotWiz()
dw['people.steve.age'] = 31

dw
# ✫(people=✫(steve=✫(age=31)))

比较dotmap

我添加了下面的快速而粗略的性能比较dotmap

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

pip install dotwiz dotmap

为了进行基准测试,我提出了以下代码:

from timeit import timeit

from dotwiz import DotWiz
from dotmap import DotMap


d = {'hey': {'so': [{'this': {'is': {'pretty': {'cool': True}}}}]}}

dw = DotWiz(d)
# ✫(hey=✫(so=[✫(this=✫(is=✫(pretty={'cool'})))]))

dm = DotMap(d)
# DotMap(hey=DotMap(so=[DotMap(this=DotMap(is=DotMap(pretty={'cool'})))]))

assert dw.hey.so[0].this['is'].pretty.cool == dm.hey.so[0].this['is'].pretty.cool

n = 100_000

print('dotwiz (create):  ', round(timeit('DotWiz(d)', number=n, globals=globals()), 3))
print('dotmap (create):  ', round(timeit('DotMap(d)', number=n, globals=globals()), 3))
print('dotwiz (get):  ', round(timeit("dw.hey.so[0].this['is'].pretty.cool", number=n, globals=globals()), 3))
print('dotmap (get):  ', round(timeit("dm.hey.so[0].this['is'].pretty.cool", number=n, globals=globals()), 3))

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

dotwiz (create):   0.189
dotmap (create):   1.085
dotwiz (get):   0.014
dotmap (get):   0.335

解决方案 17:

语言本身不支持这一点,但有时这仍然是一个有用的要求。除了 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

这将支持如下内容:

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

解决方案 18:

我最终尝试了 AttrDict和Bunch库,发现它们对我而言太慢了。我和朋友研究了一下后发现,编写这些库的主要方法会导致库积极地递归嵌套对象并在整个过程中复制字典对象。考虑到这一点,我们做了两个关键的改变。1) 我们将属性设置为延迟加载 2) 我们不是创建字典对象的副本,而是创建轻量级代理对象的副本。这是最终的实现。使用此代码的性能提升令人难以置信。当使用 AttrDict 或 Bunch 时,仅这两个库就分别消耗了我请求时间的 1/2 和 1/3(什么!?)。此代码将该时间减少到几乎为零(大约 0.5 毫秒)。这当然取决于您的需求,但如果您在代码中经常使用此功能,那么绝对可以选择像这样的简单方法。

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

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

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (tuple, list)):
        return ListProxy(value)
    return value

请参阅此处的原始实现:https: //stackoverflow.com/users/704327/michael-merickel。

需要注意的另一件事是,此实现非常简单,并未实现您可能需要的所有方法。您需要在 DictProxy 或 ListProxy 对象上根据需要编写这些方法。

解决方案 19:

这也适用于嵌套字典,并确保稍后附加的字典行为相同:

class DotDict(dict):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Recursively turn nested dicts into DotDicts
        for key, value in self.items():
            if type(value) is dict:
                self[key] = DotDict(value)

    def __setitem__(self, key, item):
        if type(item) is dict:
            item = DotDict(item)
        super().__setitem__(key, item)

    __setattr__ = __setitem__
    __getattr__ = dict.__getitem__

解决方案 20:

用于无限级别的字典、列表、字典列表和列表的字典嵌套。

它还支持酸洗

这是这个答案的扩展。

class DotDict(dict):
    # https://stackoverflow.com/a/70665030/913098
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])

    Iterable are assumed to have a constructor taking list as input.
    """

    def __init__(self, *args, **kwargs):
        super(DotDict, self).__init__(*args, **kwargs)

        args_with_kwargs = []
        for arg in args:
            args_with_kwargs.append(arg)
        args_with_kwargs.append(kwargs)
        args = args_with_kwargs

        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.items():
                    self[k] = v
                    if isinstance(v, dict):
                        self[k] = DotDict(v)
                    elif isinstance(v, str) or isinstance(v, bytes):
                        self[k] = v
                    elif isinstance(v, Iterable):
                        klass = type(v)
                        map_value: List[Any] = []
                        for e in v:
                            map_e = DotDict(e) if isinstance(e, dict) else e
                            map_value.append(map_e)
                        self[k] = klass(map_value)



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

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

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

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

    def __delitem__(self, key):
        super(DotDict, self).__delitem__(key)
        del self.__dict__[key]

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)


if __name__ == "__main__":
    import pickle
    def test_map():
        d = {
            "a": 1,
            "b": {
                "c": "d",
                "e": 2,
                "f": None
            },
            "g": [],
            "h": [1, "i"],
            "j": [1, "k", {}],
            "l":
                [
                    1,
                    "m",
                    {
                        "n": [3],
                        "o": "p",
                        "q": {
                            "r": "s",
                            "t": ["u", 5, {"v": "w"}, ],
                            "x": ("z", 1)
                        }
                    }
                ],
        }
        map_d = DotDict(d)
        w = map_d.l[2].q.t[2].v
        assert w == "w"

        pickled = pickle.dumps(map_d)
        unpickled = pickle.loads(pickled)
        assert unpickled == map_d

        kwargs_check = DotDict(a=1, b=[dict(c=2, d="3"), 5])
        assert kwargs_check.b[0].d == "3"

        kwargs_and_args_check = DotDict(d, a=1, b=[dict(c=2, d="3"), 5])
        assert kwargs_and_args_check.l[2].q.t[2].v == "w"
        assert kwargs_and_args_check.b[0].d == "3"



    test_map()

解决方案 21:

def dict_to_object(dick):
    # http://stackoverflow.com/a/1305663/968442

    class Struct:
        def __init__(self, **entries):
            self.__dict__.update(entries)

    return Struct(**dick)

如果决定将其永久转换dict为对象,则应该这样做。您可以在访问之前创建一个一次性对象。

d = dict_to_object(d)

解决方案 22:

此解决方案是对epool提供的解决方案的改进,旨在满足 OP 以一致的方式访问嵌套字典的要求。epool 的解决方案不允许访问嵌套字典。

class YAMLobj(dict):
    def __init__(self, args):
        super(YAMLobj, self).__init__(args)
        if isinstance(args, dict):
            for k, v in args.iteritems():
                if not isinstance(v, dict):
                    self[k] = v
                else:
                    self.__setattr__(k, YAMLobj(v))


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

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

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

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

    def __delitem__(self, key):
        super(YAMLobj, self).__delitem__(key)
        del self.__dict__[key]

有了这个类,我们现在可以做类似的事情:A.B.C.D

解决方案 23:

使用namedtuple允许点访问。

它就像一个轻量级对象,也具有元组的属性。

它允许定义属性并使用点运算符访问它们。

from collections import namedtuple
Data = namedtuple('Data', ['key1', 'key2'])

dataObj = Data(val1, key2=val2) # can instantiate using keyword arguments and positional arguments

使用点运算符访问

dataObj.key1 # Gives val1
datObj.key2 # Gives val2

使用元组索引进行访问

dataObj[0] # Gives val1
dataObj[1] # Gives val2

但请记住这是一个元组,而不是一个字典。因此下面的代码会报错

dataObj['key1'] # Gives TypeError: tuple indices must be integers or slices, not str

参考:namedtuple

解决方案 24:

这是一个老问题,但我最近发现sklearn有一个可以通过密钥访问的实现版本dict,即Bunch
https://scikit-learn.org/stable/modules/generated/sklearn.utils.Bunch.html#sklearn.utils.Bunch

解决方案 25:

最简单的解决方案。

定义一个只有 pass 语句的类。为该类创建对象并使用点符号。

class my_dict:
    pass

person = my_dict()
person.id = 1 # create using dot notation
person.phone = 9999
del person.phone # Remove a property using dot notation

name_data = my_dict()
name_data.first_name = 'Arnold'
name_data.last_name = 'Schwarzenegger'

person.name = name_data
person.name.first_name # dot notation access for nested properties - gives Arnold

解决方案 26:

获取点访问(但不是数组访问)的一个简单方法是使用 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"}

解决方案 27:

@derek73 的答案非常简洁,但无法进行 pickle 或 (深度) 复制,并且会None因缺少键而返回。下面的代码修复了这个问题。

编辑:我没有看到上面的答案解决完全相同的问题(已投票)。我把答案留在这里供参考。

class dotdict(dict):
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

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

解决方案 28:

我只需要使用点路径字符串来访问字典,所以我想到了:

def get_value_from_path(dictionary, parts):
    """ extracts a value from a dictionary using a dotted path string """

    if type(parts) is str:
        parts = parts.split('.')

    if len(parts) > 1:
        return get_value_from_path(dictionary[parts[0]], parts[1:])

    return dictionary[parts[0]]

a = {'a':{'b':'c'}}
print(get_value_from_path(a, 'a.b')) # c

解决方案 29:

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

这可能对测试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

解决方案 30:

最佳和完整的实施

from typing import Any

class DotDict(dict):
    """
    dot.notation access to dictionary attributes
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for key, value in self.items():
            if isinstance(value, dict):
                self[key] = DotDict(value)

    def __setitem__(self, key: Any, item: Any) -> None:
        if isinstance(item, dict):
            item = DotDict(item)
        super().__setitem__(key, item)

    def __getitem__(self, key: Any) -> Any:
        return super().__getitem__(key)

    def __setattr__(self, key: Any, item: Any) -> None:
        return self.__setitem__(key, item)

    def __getattr__(self, key: Any) -> Any:
        return self.__getitem__(key)

    def __missing__(self, key: Any) -> str:
        raise KeyError(f"DotDict object has no item '{key}'")

    def __getstate__(self) -> dict:
        return self

    def __setstate__(self, state: dict) -> None:
        self.update(state)
        self.__dict__ = self

    def __delattr__(self, item: Any) -> None:
        self.__delitem__(item)

    def __delitem__(self, key: Any) -> None:
        super().__delitem__(key)

测试:

# Create a DotDict instance
d = DotDict()

# Test __setattr__ method
d.foo = "bar"
assert d.foo == "bar"

# Test __getattr__ method
assert d.foo == "bar"

# Test __getitem__ method
assert d["foo"] == "bar"

# Test __setitem__ method
d["baz"] = "qux"
assert d.baz == "qux"

# Test nested dictionaries
d.nested = {"nested_key": "nested_value"}
assert d.nested.nested_key == "nested_value"

# Test nested update
d.nested.nested_key = "new_value"
assert d.nested.nested_key == "new_value"

# Test __delattr__ method
del d.foo
try:
    _ = d.foo
except KeyError as e:
    assert e.args[0] == "DotDict object has no item 'foo'"

# Test __delitem__ method
del d["baz"]
try:
    _ = d.baz
except KeyError as e:
    assert e.args[0] == "DotDict object has no item 'baz'"

# Test __getstate__ method
state = d.__getstate__()
assert state == {"nested": {"nested_key": "new_value"}}

# Test __setstate__ method
new_d = DotDict()
new_d.__setstate__(state)
assert new_d.nested.nested_key == "new_value"
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1124  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   79  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   70  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   82  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   74  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用