Pourquoi mon python OrderedDict est-il initialisé 'hors service'?
La solution ici est moins intrigante que l'explication. Il y a quelque chose ici que je ne comprends tout simplement pas, et peut-être qu'une explication aiderait les autres aussi bien que moi.
>>> 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
De les docs :
Le constructeur OrderedDict et la méthode
update()
acceptent tous les deux des arguments de mot clé, mais leur ordre est perdu car la fonction Python appelle des arguments de mot de passe de sémantique d'appel en utilisant un dictionnaire ordinaire non ordonné.
Ainsi, l'initialisation perd l'ordre, car il s'agit essentiellement d'appeler un constructeur avec **kwargs
.
Edit: En termes de solution (pas seulement une explication) - comme indiqué dans un commentaire de l'OP , en passant dans une seule liste de tuples va travailler:
>>> 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
C'est parce qu'il ne reçoit qu'un seul argument, une liste.
@Chris Krycho a bien expliqué pourquoi les choses échouent.
Si vous regardez le repr () d'un OrderedDict, vous obtenez un indice sur la façon de donner l'ordre depuis le début: vous devez utiliser une liste de paires (clé, valeur) pour conserver l'ordre des clés donné par la liste.
En voici un que j'ai fait plus tôt:
>>> 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']
>>>
(Il se trouve que dans Python v3.3.0 votre exemple original de spam
a gardé les clés dans leur ordre d'origine dès le début. J'ai changé pour spamher
pour en savoir plus).
Comme le autreréponses l'ont mentionné, essayer de passer un dict à OrderedDict ou utiliser des arguments de mots clés ne préserve pas l'ordre. Passer des tuples est un peu moche, cependant, et c'est Python. Ça devrait être beau.
Vous pouvez un Butilisation __getitem__
sur une classe afin d'avoir une syntaxe de type dict pour créer des "littéraux" 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()
Vous pouvez maintenant utiliser une syntaxe de type dict pour créer un OrderedDict:
spam = OD['s': (1, 2),
'p': (3, 4),
'a': (5, 6),
'm': (7, 8)]
assert(''.join(spam.keys()) == 'spam')
Cela fonctionne car à l'intérieur des crochets, Python crée tranche littéraux, qui se présentent comme la syntaxe dict si vous plissez les yeux un peu.
La classe OD
pourrait bénéficier de la vérification des erreurs, mais cela montre comment cela peut fonctionner.