Comment renvoyer des clés de dictionnaire sous forme de liste en Python?

784

En Python 2.7 , je pouvais obtenir des clés de dictionnaire , des valeurs ou des éléments sous forme de liste:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

Maintenant, en Python> = 3.3 , j'obtiens quelque chose comme ceci:

>>> newdict.keys()
dict_keys([1, 2, 3])

Donc, je dois le faire pour obtenir une liste:

newlist = list()
for i in newdict.keys():
    newlist.append(i)

Je me demande, y a-t-il une meilleure façon de retourner une liste en Python 3 ?

Dimitris Fasarakis Hilliard
la source
Un problème de sécurité des threads intéressant sur ce sujet est ici: blog.labix.org/2008/06/27/…
Paul
2
Je suis nouveau sur Python et il me semble que cette prolifération de nouveaux types de données inutiles est l'un des pires aspects de Python. À quoi sert ce type de données dict_keys? Pourquoi pas une liste?
Phil Goetz

Réponses:

979

Essayez list(newdict.keys()).

Cela convertira l' dict_keysobjet en une liste.

D'un autre côté, vous devez vous demander si cela importe ou non. La façon Pythonique de coder consiste à assumer la frappe de canard ( si cela ressemble à un canard et qu'il se casse comme un canard, c'est un canard ). L' dict_keysobjet agira comme une liste dans la plupart des cas. Par exemple:

for key in newdict.keys():
  print(key)

De toute évidence, les opérateurs d'insertion peuvent ne pas fonctionner, mais cela n'a pas beaucoup de sens pour une liste de clés de dictionnaire de toute façon.

Chris
la source
49
newdict.keys () ne prend pas en charge l'indexation
gypaetus
57
list(newdict)fonctionne également (au moins en python 3.4). Y a-t-il une raison d'utiliser la .keys()méthode?
naught101
46
Remarque: dans le débogueur pdb> list(newdict.keys()) échoue car il se heurte à la commande pdb du même nom. Utilisez pdb> !list(newdict.keys())pour échapper aux commandes pdb.
Riaz Rizvi
24
@ naught101 Oui, .keys()est bien plus clair sur ce qui se passe.
Felix D.
2
Notez que si vous utilisez list (newdict.keys ()), les clés ne sont pas dans l'ordre dans lequel vous les avez placées en raison de l'ordre de hachage!
Nate M
278

Python> = 3.5 alternative: décompresser dans une liste littérale [*newdict]

De nouvelles généralisations de déballage (PEP 448) ont été introduites avec Python 3.5 vous permettant désormais de faire facilement:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

Le décompactage *fonctionne avec n'importe quel objet qui est itérable et, puisque les dictionnaires renvoient leurs clés lorsqu'ils sont itérés, vous pouvez facilement créer une liste en l'utilisant dans un littéral de liste.

L'ajout de .keys()ie [*newdict.keys()]pourrait aider à rendre votre intention un peu plus explicite, mais cela vous coûtera une recherche et une invocation de fonction. (ce qui, en toute honnêteté, n'est pas quelque chose dont vous devriez vraiment vous inquiéter).

La *iterablesyntaxe est similaire à faire list(iterable)et son comportement a été initialement documenté dans la section Appels du manuel de référence Python. Avec le PEP 448, la restriction sur l'endroit où *iterablepourrait apparaître a été assouplie, ce qui permet de le placer également dans les littéraux de liste, de set et de tuple, le manuel de référence sur les listes d'expressions a également été mis à jour pour l'indiquer.


Bien qu'équivalent à list(newdict)la différence qu'il est plus rapide (au moins pour les petits dictionnaires) car aucun appel de fonction n'est réellement effectué:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

avec des dictionnaires plus grands, la vitesse est à peu près la même (le surcoût lié à l'itération dans une grande collection l'emporte sur le faible coût d'un appel de fonction).


De la même manière, vous pouvez créer des tuples et des ensembles de clés de dictionnaire:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

méfiez-vous de la virgule de fin dans le tuple case!

Dimitris Fasarakis Hilliard
la source
grande explication, mais veuillez vous référer à n'importe quel lien qui décrit ce type de syntaxe "* newdict", je veux dire comment et pourquoi cela renvoie les clés du dictionnaire juste pour la compréhension.Merci
Muhammad Younus
1
@MYounas Cette syntaxe est disponible depuis un certain temps, même en Python 2. Dans les appels de fonction, vous pouvez faire def foo(*args): print(args)suivi foo(*{1:0, 2:0})du résultat en (1, 2)cours d'impression. Ce comportement est spécifié dans la section Appels du manuel de référence. Python 3.5 avec PEP 448 vient de desserrer les restrictions sur l'endroit où celles-ci peuvent apparaître, ce [*{1:0, 2:0}]qui permet désormais de les utiliser. Quoi qu'il en soit, je vais modifier ma réponse et les inclure.
Dimitris Fasarakis Hilliard
1
*newdict- c'est certainement la réponse pour les golfeurs de code; P. Aussi: ce qui, en toute honnêteté, n'est pas quelque chose dont vous devriez vraiment vous inquiéter - et si vous l'êtes, n'utilisez pas python .
Artemis ne fait toujours pas confiance au SE
46

list(newdict)fonctionne à la fois dans Python 2 et Python 3, fournissant une liste simple des clés dans newdict. keys()n'est pas nécessaire. (:

Seb
la source
26

Un peu sur la définition de "typage du canard" - dict.keys()renvoie un objet itérable, pas un objet de type liste. Cela fonctionnera partout où un itérable fonctionnera - pas n'importe où une liste fonctionnera. une liste est aussi un itérable, mais un itérable n'est PAS une liste (ou séquence ...)

Dans les cas d'utilisation réels, la chose la plus courante à faire avec les touches d'un dict est de les parcourir, donc cela a du sens. Et si vous en avez besoin comme liste, vous pouvez appeler list().

De la même manière, car zip()- dans la grande majorité des cas, elle est répétée - pourquoi créer une toute nouvelle liste de tuples juste pour l'itérer puis la jeter à nouveau?

Cela fait partie d'une grande tendance en python à utiliser plus d'itérateurs (et de générateurs), plutôt que des copies de listes partout.

dict.keys() devrait fonctionner avec des compréhensions, cependant - vérifiez attentivement les fautes de frappe ou quelque chose ... cela fonctionne bien pour moi:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
Chris Barker
la source
2
Vous n'avez même pas besoin d'utiliser .keys(); l'objet dictionnaire est lui - même itérables et produit des clés lorsque itéré: [key.split(", ") for key in d].
Martijn Pieters
25

Vous pouvez également utiliser une compréhension de liste :

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

Ou, plus court,

>>> [k  for  k in  newdict]
[1, 2, 3]

Remarque: L'ordre n'est pas garanti sur les versions sous 3.7 (la commande n'est encore qu'un détail d'implémentation avec CPython 3.6).

未来 陆家嘴 顶尖 的 投资 人
la source
6
Utilisez simplement list(newdict). Il n'est pas nécessaire de comprendre la liste ici.
Martijn Pieters
8

La conversion en liste sans utiliser la keysméthode la rend plus lisible:

list(newdict)

et, lorsque vous parcourez les dictionnaires, vous n'avez pas besoin de keys():

for key in newdict:
    print key

sauf si vous le modifiez dans la boucle qui nécessiterait une liste de clés préalablement créée:

for key in list(newdict):
    del newdict[key]

Sur Python 2, il y a un gain de performance marginal en utilisantkeys() .

Cas
la source
8

Si vous devez stocker les clés séparément, voici une solution qui nécessite moins de saisie que toutes les autres solutions présentées jusqu'à présent, en utilisant Extended Iterable Unpacking (python3.x +).

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

            ╒═══════════════╤═════════════════════════════════════════╕
             k = list(d)      9 characters (excluding whitespace)   
            ├───────────────┼─────────────────────────────────────────┤
             k = [*d]         6 characters                          
            ├───────────────┼─────────────────────────────────────────┤
             *k, = d          5 characters                          
            ╘═══════════════╧═════════════════════════════════════════╛
cs95
la source
1
La seule petite mise en garde que je voudrais signaler est que kc'est toujours une liste ici. Si un utilisateur veut un tuple ou un ensemble à partir des clés, il devra revenir aux autres options.
Dimitris Fasarakis Hilliard
1
Une note plus notable est le fait que, en tant qu'instruction, *k, = da des limites sur l'endroit où il peut apparaître (mais voir, et peut-être mettre à jour cette réponse pour, PEP 572 - le déballage étendu n'est pas pris en charge pour les expressions d'affectation atm mais cela pourrait arriver un jour! )
Dimitris Fasarakis Hilliard
que faire si vous voulez à la fois les clés et les valeurs des listes?
endolith
1
@endolith peut-être keys, vals = zip(*d.items())(bien que cela donne deux tuples, assez près). Je ne connais pas une expression plus courte que celle-ci.
cs95
1

Je peux penser à 2 façons d'extraire les clés du dictionnaire.

Méthode 1: - Pour obtenir les clés à l'aide de la méthode .keys () puis les convertir en liste.

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

Méthode 2: - Pour créer une liste vide, puis ajouter des clés à la liste via une boucle. Vous pouvez également obtenir les valeurs avec cette boucle (utilisez .keys () pour les clés uniquement et .items () pour l'extraction des clés et des valeurs)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']
Rahul
la source