Подтвердить что ты не робот

Инициация Python OrderedDict

Почему мой 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
4b9b3361

Ответ 1

От документы:

Конструктор OrderedDict и метод update() принимают аргументы ключевого слова, но их порядок теряется, потому что функция Pythons вызывает семантические аргументы аргументов pass-in с использованием обычного неупорядоченного словаря.

Таким образом, инициализация теряет порядок, потому что она в основном вызывает конструктор с **kwargs.

Изменить: В терминах решения (а не просто объяснения) - указано в в комментарии 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

Это потому, что он получает только один аргумент, список.

Ответ 2

@Крис Кричо дал хорошее объяснение, почему все терпит неудачу.

Если вы посмотрите на repr() OrderedDict, вы получите подсказку о том, как передать заказ с самого начала: вам нужно использовать список пар (ключ, значение), чтобы сохранить порядок ключей, заданных список.

Здесь я сделал это раньше:

>>> 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, чтобы получить это).

Ответ 3

Как упомянули другие ответы, пытаясь передать dict в OrderedDict или используя аргументы ключевого слова doesn Не сохраняй приказ. Прохождение в кортежах является довольно уродливым, хотя, и это Python. Это должно быть красиво.

Вы можете ab использовать __getitem__ для класса, чтобы иметь диктофонный синтаксис для создания литералов OrderedDict:

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()

Теперь вы можете использовать диктофонный синтаксис для создания OrderedDict:

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

Это работает, потому что внутри квадратных скобок Python создает slice литералы, которые выглядят как синтаксис dict, если вы немного прищурились.

Класс OD может извлечь выгоду из проверки ошибок, но это демонстрирует, как он может работать.