我发现访问字典键更方便obj.foo
代替obj['foo']
,所以我写了这个片段:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
不过,我认为一定有某种原因导致 Python 没有提供开箱即用的此功能。以这种方式访问字典键有什么注意事项和陷阱?
更新 - 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()
工作得很好。除非 - 当然 - 你为它们分配了一些值,见下文)
- 属性和项目始终同步
- 尝试访问不存在的键作为属性正确引发
AttributeError
代替KeyError
- 支持[Tab]自动补全(例如在 jupyter 和 ipython 中)
Cons:
- 方法如
.keys()
will not如果它们被传入数据覆盖,则工作正常
- 导致一个内存泄漏在 Python
- Pylint 很疯狂
E1123(unexpected-keyword-arg)
and E1103(maybe-no-member)
- 对于外行来说,这似乎纯粹是魔法。
关于其工作原理的简短说明
- 所有Python对象在内部将它们的属性存储在一个名为的字典中
__dict__
.
- 没有要求内部词典
__dict__
需要是“只是一个简单的字典”,所以我们可以分配任何子类dict()
到内部词典。
- 在我们的例子中,我们只需分配
AttrDict()
我们正在实例化的实例(就像我们在__init__
).
- 通过致电
super()
's __init__()
方法我们确保它(已经)的行为与字典完全相同,因为该函数调用所有字典实例化 code.
Python 不提供开箱即用的功能的原因之一
正如“缺点”列表中所述,这将存储密钥的命名空间(可能来自任意和/或不受信任的数据!)与内置 dict 方法属性的命名空间结合在一起。例如:
d = AttrDict()
d.update({'items':["jacket", "necktie", "trousers"]})
for k, v in d.items(): # TypeError: 'list' object is not callable
print "Never reached!"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)