Python OrderedDict迭代

2024-05-16 18:08:03 发布

您现在位置:Python中文网/ 问答频道 /正文

为什么我的python OrderedDict被初始化为“无序”?

这里的解决方案没有解释那么有趣。这里有些东西我就是不明白,也许一个解释会帮助别人和我一样。

>>> from collections import OrderedDict

>>> spam = OrderedDict(s = (1, 2), p = (3, 4), a = (5, 6), m = (7, 8))

>>> spam
OrderedDict([('a', (5, 6)), ('p', (3, 4)), ('s', (1, 2)), ('m', (7, 8))])

>>> for key in spam.keys():
...    print key    
...
#  this is 'ordered' but not the order I wanted....
a
p
s
m

# I was expecting (and wanting):
s
p
a
m

Tags: keyinfromimportforiskeysspam
3条回答

@Chris Krycho很好地解释了为什么事情会失败。

如果您查看OrderedDict的repr(),您会得到一个如何从一开始就传递顺序的提示:您需要使用(键、值)对的列表来保持列表中给定键的顺序。

我之前做过一个:

>>> from collections import OrderedDict
>>> spamher = OrderedDict(s=6, p=5, a=4, m=3, h=2, e=1, r=0)
>>> spamher
OrderedDict([('h', 2), ('m', 3), ('r', 0), ('s', 6), ('p', 5), ('a', 4), ('e', 1)])
>>> 
>>> list(spamher.keys())
['h', 'm', 'r', 's', 'p', 'a', 'e']
>>> 
>>> spamher = OrderedDict([('s', 6), ('p', 5), ('a', 4), ('m', 3), ('h', 2), ('e', 1), ('r', 0)])
>>> list(spamher.keys())
['s', 'p', 'a', 'm', 'h', 'e', 'r']
>>> 

(恰好在Python v3.3.0中,spam的原始示例从一开始就保持键的原始顺序。我改成了spamher来解决这个问题)。

正如otheranswers所提到的,试图将dict传递给orderedict或使用关键字参数并不能保持顺序。不过,传入元组有点难看,这是Python。它应该很漂亮。

您可以对类使用__getitem__,以便使用类似dict的语法创建OrderedDict“literals”:

from collections import OrderedDict
class OD(object):
    """This class provides a nice way to create OrderedDict "literals"."""
    def __getitem__(self, slices):
        if not isinstance(slices, tuple):
            slices = slices,
        return OrderedDict((slice.start, slice.stop) for slice in slices)
# Create a single instance; we don't ever need to refer to the class.
OD = OD()

现在可以使用类似dict的语法创建OrderedDict:

spam = OD['s': (1, 2), 
          'p': (3, 4), 
          'a': (5, 6), 
          'm': (7, 8)]
assert(''.join(spam.keys()) == 'spam')

这是因为在方括号内,Python创建slice文本,如果您稍微斜视一下,这些文本看起来就像dict语法。

OD类可以从错误检查中获益,但这演示了它如何工作。

来自the docs

The OrderedDict constructor and update() method both accept keyword arguments, but their order is lost because Python’s function call semantics pass-in keyword arguments using a regular unordered dictionary.

因此初始化失去了顺序,因为它基本上是用**kwargs调用构造函数。

编辑:根据解决方案(不仅仅是解释)-正如in a comment by the OP所指出的,传入一个元组列表工作:

>>> from collections import OrderedDict
>>> spam = OrderedDict([('s',(1,2)),('p',(3,4)),('a',(5,6)),('m',(7,8))])
>>> for key in spam:
...     print(key)
...
s
p
a
m
>>> for key in spam.keys():
...     print(key)
...
s
p
a
m

这是因为它只得到一个参数,一个列表。

相关问题 更多 >