像属性一样访问字典键? [英] Accessing dict keys like an attribute?

查看:32
本文介绍了像属性一样访问字典键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I find it more convenient to access dict keys as obj.foo instead of obj['foo'], so I wrote this snippet:

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

然而,我认为一定有某种原因,Python 没有提供这种开箱即用的功能.以这种方式访问​​ dict 键有哪些注意事项和陷阱?

However, I assume that there must be some reason that Python doesn't provide this functionality out of the box. What would be the caveats and pitfalls of accessing dict keys in this manner?

推荐答案

更新 - 2020

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

Update - 2020

Since this question was asked almost ten years ago, quite a bit has changed in Python itself since then.

虽然我的原始答案中的方法在某些情况下仍然有效(例如,遗留项目坚持使用旧版本的 Python 以及您确实需要使用非常动态的字符串键处理字典的情况),但我认为一般来说 <在 Python 3.7 中引入的 href="https://docs.python.org/3/library/dataclasses.html" rel="noreferrer">dataclasses 是绝大多数用例的明显/正确的解决方案AttrDict.

While the approach in my original answer is still valid for some cases, (e.g. legacy projects stuck to older versions of Python and cases where you really need to handle dictionaries with very dynamic string keys), I think that in general the dataclasses introduced in Python 3.7 are the obvious/correct solution to vast majority of the use cases of AttrDict.

最好的方法是:

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

一些优点:

  • 它确实有效!
  • 没有隐藏字典类方法(例如 .keys() 工作得很好.除非 - 当然 - 你给它们分配一些值,见下文)
  • 属性和项目始终同步
  • 尝试访问不存在的键作为属性正确引发 AttributeError 而不是 KeyError
  • 支持 [Tab] 自动完成(例如在 jupyter 和 ipython 中)
  • It actually works!
  • No dictionary class methods are shadowed (e.g. .keys() work just fine. Unless - of course - you assign some value to them, see below)
  • Attributes and items are always in sync
  • Trying to access non-existent key as an attribute correctly raises AttributeError instead of KeyError
  • Supports [Tab] autocompletion (e.g. in jupyter & ipython)

缺点:

  • Methods like .keys() will not work just fine if they get overwritten by incoming data
  • Causes a memory leak in Python < 2.7.4 / Python3 < 3.2.3
  • Pylint goes bananas with E1123(unexpected-keyword-arg) and E1103(maybe-no-member)
  • For the uninitiated it seems like pure magic.
  • 所有 python 对象在内部将它们的属性存储在一个名为 __dict__ 的字典中.
  • 没有要求内部字典 __dict__ 需要只是一个普通的 dict",因此我们可以将 dict() 的任何子类分配给内部字典.
  • 在我们的例子中,我们只是简单地分配我们正在实例化的 AttrDict() 实例(就像我们在 __init__ 中一样).
  • 通过调用super()__init__() 方法,我们确保它(已经)表现得与字典完全一样,因为该函数调用了所有字典实例化代码.
  • 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.

如缺点"中所述列表,这结合了存储键的命名空间(可能来自任意和/或不受信任的数据!)与内置 dict 方法属性的命名空间.例如:

As noted in the "cons" list, this combines the namespace of stored keys (which may come from arbitrary and/or untrusted data!) with the namespace of builtin dict method attributes. For example:

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

这篇关于像属性一样访问字典键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆