我发现它更方便访问字典键作为obj。foo而不是obj['foo'],所以我写了这个片段:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

然而,我认为一定有一些原因,Python没有提供开箱即用的功能。以这种方式访问字典键的注意事项和缺陷是什么?


当前回答

最简单的方法是定义一个类,我们称之为Namespace。在字典上使用对象dict.update()。然后,字典将被视为一个对象。

class Namespace(object):
    '''
    helps referencing object in a dictionary as dict.key instead of dict['key']
    '''
    def __init__(self, adict):
        self.__dict__.update(adict)



Person = Namespace({'name': 'ahmed',
                     'age': 30}) #--> added for edge_cls


print(Person.name)

其他回答

从另一个SO问题中,有一个很好的实现示例,可以简化现有的代码。如何:

class AttributeDict(dict):
    __slots__ = () 
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__

更加简洁,并且不会为将来的__getattr__和__setattr__函数留下任何额外的麻烦空间。

最简单的方法是定义一个类,我们称之为Namespace。在字典上使用对象dict.update()。然后,字典将被视为一个对象。

class Namespace(object):
    '''
    helps referencing object in a dictionary as dict.key instead of dict['key']
    '''
    def __init__(self, adict):
        self.__dict__.update(adict)



Person = Namespace({'name': 'ahmed',
                     'age': 30}) #--> added for edge_cls


print(Person.name)

更新- 2020年

自从这个问题在大约十年前被提出以来,Python本身已经发生了相当大的变化。

虽然我最初回答中的方法在某些情况下仍然有效,(例如,遗留项目坚持使用旧版本的Python,以及在某些情况下,您确实需要处理具有非常动态字符串键的字典),但我认为一般来说,Python 3.7中引入的数据类是AttrDict绝大多数用例的明显/正确的解决方案。

原来的答案

最好的方法是:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

一些优点:

它真的有用! 没有字典类方法被遮蔽(例如.keys()工作得很好。除非-当然-你给它们赋值,见下文) 属性和项总是同步的 试图将不存在的key作为属性访问会正确地引发AttributeError而不是KeyError 支持[Tab]自动补全(例如在jupyter和ipython中)

缺点:

如果.keys()等方法被传入的数据覆盖,它们就不能正常工作 在Python < 2.7.4 / Python3 < 3.2.3中导致内存泄漏 Pylint因为E1123(意外关键字参数)和E1103(可能没有成员)而抓狂 对于外行来说,这似乎是纯粹的魔法。

简要解释一下它是如何工作的

All python objects internally store their attributes in a dictionary that is named __dict__. There is no requirement that the internal dictionary __dict__ would need to be "just a plain dict", so we can assign any subclass of dict() to the internal dictionary. In our case we simply assign the AttrDict() instance we are instantiating (as we are in __init__). By calling super()'s __init__() method we made sure that it (already) behaves exactly like a dictionary, since that function calls all the dictionary instantiation code.

Python没有开箱即用提供此功能的原因之一

正如“cons”列表中所指出的,这将存储键的名称空间(可能来自任意和/或不受信任的数据!)与内置dict方法属性的名称空间结合在一起。例如:

d = AttrDict()
d.update({'items':["jacket", "necktie", "trousers"]})
for k, v in d.items():    # TypeError: 'list' object is not callable
    print "Never reached!"

一般情况下它不成立。不是所有有效的dict键都有可寻址的属性(“键”)。所以,你要小心。

Python对象基本上都是字典。所以我怀疑会有什么表现或其他惩罚。

为了给答案增加一些变化,sci-kit learn将其实现为一串:

class Bunch(dict):                                                              
    """ Scikit Learn's container object                                         

    Dictionary-like object that exposes its keys as attributes.                 
    >>> b = Bunch(a=1, b=2)                                                     
    >>> b['b']                                                                  
    2                                                                           
    >>> b.b                                                                     
    2                                                                           
    >>> b.c = 6                                                                 
    >>> b['c']                                                                  
    6                                                                           
    """                                                                         

    def __init__(self, **kwargs):                                               
        super(Bunch, self).__init__(kwargs)                                     

    def __setattr__(self, key, value):                                          
        self[key] = value                                                       

    def __dir__(self):                                                          
        return self.keys()                                                      

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

    def __setstate__(self, state):                                              
        pass                       

您所需要的是获取setattr和getattr方法—getattr检查字典键,然后继续检查实际属性。setstaet是针对pickle /unpickling“bunch”的修复-如果感兴趣,请检查https://github.com/scikit-learn/scikit-learn/issues/6196