• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

像属性一样访问字典键?

用户头像
it1352
帮助1

问题说明

我发现以 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?

正确答案

#1

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /reply/detail/tanhcfhcig
系列文章
更多 icon
同类精品
更多 icon
继续加载