问题描述
我发现以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一定有某些原因没有提供开箱即用的功能.以这种方式访问字典键会带来哪些警告和陷阱?
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?
推荐答案
做到这一点的最佳方法是:
The best way to do this is:
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
一些优点:
- 它确实有效!
- 没有遮蔽字典类的方法(例如
.keys()
可以正常工作.除非-当然-您为其分配了一些值,请参见下文) - 属性和项目始终保持同步
- 尝试将不存在的键作为属性正确访问会引发
AttributeError
而不是KeyError
- 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 ofKeyError
缺点:
-
.keys()
之类的方法如果被传入数据覆盖,将不能正常工作 - 在Python中导致内存泄漏. 2.7.4/Python3< 3.2.3
- Pylint与
E1123(unexpected-keyword-arg)
和E1103(maybe-no-member)
成为香蕉 - 对于初学者来说,这似乎是纯粹的魔术.
- 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)
andE1103(maybe-no-member)
- For the uninitiated it seems like pure magic.
- 所有python对象在内部将其属性存储在名为
__dict__
的字典中. - 不要求内部字典
__dict__
必须是仅是简单的字典",因此我们可以将dict()
的任何子类分配给内部字典. - 在本例中,我们仅分配要实例化的
AttrDict()
实例(就像在__init__
中一样). - 通过调用
super()
的__init__()
方法,我们确保它(已经)的行为与字典完全相同,因为该函数调用了所有 dictionary实例化代码.
- 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 ofdict()
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.
如"cons"列表中所述,这将存储键的名称空间(可能来自任意和/或不受信任的数据!)与内置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!"
这篇关于访问像属性一样的字典键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!