我在哪里回答所问的问题
为什么Python不提供开箱即用的功能?
我怀疑这与Python的Zen有关:“应该有一种-最好只有一种-显而易见的方法。” 这将创建两种显而易见的方式来访问字典中的值:obj['key']
和obj.key
。
注意事项和陷阱
这些可能包括代码不够清晰和混乱。也就是说,以下内容可能会使以后打算维护您代码的其他人感到困惑,甚至如果您暂时不使用它,也可能会使您感到困惑。再次,来自禅宗:“可读性很重要!”
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
如果d
被实例化, KEY
被定义或被 d[KEY]
分配为远离d.spam
使用的地方,则它很容易导致对正在执行的操作感到困惑,因为这不是常用的习惯用法。我知道这可能会使我感到困惑。
另外,如果您KEY
按如下方式更改值(但未更改d.spam
),则您将获得:
>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'
海事组织,不值得付出努力。
其他项目
正如其他人指出的那样,您可以使用任何可哈希对象(不仅仅是字符串)作为dict键。例如,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
是合法的,但是
>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
File "<stdin>", line 1
d.(2, 3)
^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>>
不是。这使您可以访问字典键的所有可打印字符或其他可哈希对象的范围,而访问对象属性时则没有这些范围。这使诸如缓存对象元类之类的魔术成为可能,例如Python Cookbook(第9章)中的配方。
我在其中编辑
我更喜欢的美学spam.eggs
过spam['eggs']
(我认为它看起来更清洁),我真的开始渴望这个功能时,我遇到了namedtuple
。但是能够执行以下操作的便利性胜过它。
>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>
这是一个简单的示例,但是我经常发现自己在不同情况下使用dict而不是使用obj.key
符号(即,当我需要从XML文件读取首选项时)。在其他情况下,出于美学原因,我倾向于实例化动态类并在其上添加一些属性,我将继续使用dict来保持一致性,以增强可读性。
我确信OP早就解决了这个问题,使他满意,但是如果他仍然想要此功能,那么我建议他从pypi下载提供该功能的软件包之一:
束是我更熟悉的一种。的子类dict
,因此您具有所有功能。
AttrDict看起来也很不错,但是我并不熟悉它,也没有像 Bunch那样详细地浏览源代码。
- Addict会得到积极维护,并提供类似attr的访问权限。
- 如Rotareti的评论所述,Bunch已过时,但有一个名为Munch的活动叉子。
但是,为了提高代码的可读性,我强烈建议他不要混合使用自己的符号样式。如果他喜欢这种表示法,那么他应该简单地实例化一个动态对象,为其添加所需的属性,然后将其命名为day:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
我在其中更新,以在评论中回答后续问题
在下面的评论中,Elmo问:
如果您想更深入一点怎么办?(指type(...))
尽管我从未使用过这种用例(再次dict
,为了保持一致性,我倾向于使用nested ),但是以下代码可以工作:
>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
... setattr(d, x, C())
... i = 1
... for y in 'one two three'.split():
... setattr(getattr(d, x), y, i)
... i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}
collections.namedtuple
为此非常有用。