像访问属性一样访问dict键?

2024-04-25 13:09:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我发现以obj.foo而不是obj['foo']的形式访问dict键更方便,所以我编写了以下代码片段:

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

但是,我认为Python没有提供这种现成的功能肯定是有原因的。以这种方式访问dict密钥的注意事项和陷阱是什么?


Tags: 代码self功能objreturnfoovaluedef
3条回答

如果使用数组表示法,则可以将所有合法字符串作为键的一部分。 例如,obj['!#$%^&*()_']

最好的方法是:

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

一些优点:

  • 它确实有效!
  • 没有字典类方法被隐藏(例如,.keys()工作正常)
  • 属性和项总是同步的
  • 试图以属性的形式访问不存在的键时,会引发AttributeError,而不是KeyError

缺点:

  • .keys()这样的方法如果被传入的数据覆盖,它们就不会工作得很好
  • 在Python<;2.7.4/Python3<;3.2.3中导致memory leak
  • 派林和E1123(unexpected-keyword-arg)E1103(maybe-no-member)一起去吃香蕉
  • 对于外行来说,这似乎是纯粹的魔法。

关于它如何工作的简短解释

  • 所有python对象都在内部将其属性存储在名为__dict__的字典中。
  • 没有要求内部字典__dict__必须是“纯dict”,因此我们可以将dict()的任何子类分配给内部字典。
  • 在我们的例子中,我们只需分配我们正在实例化的AttrDict()实例(就像我们在__init__中一样)。
  • 通过调用super()__init__()方法,我们确保它(已经)的行为与字典完全一样,因为该函数调用所有的字典实例化代码。

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!"

This other SO question中有一个很好的实现示例,它简化了您现有的代码。怎么样:

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

更简洁,不会给将来进入__getattr____setattr__函数留下任何空间。

相关问题 更多 >