web-dev-qa-db-fra.com

Pourquoi Python 3 a-t-il besoin que dict.items soit entouré de list ()?

J'utilise Python 3. Je viens d'installer un Python IDE et je suis curieux de connaître le code suivant) Attention:

features = { ... }
for k, v in features.items():
    print("%s=%s" % (k, v))

L'avertissement est: "Pour le support Python3 devrait ressembler à ... list(features.items())"

Il y a aussi une mention à ce sujet sur http://docs.python.org/2/library/2to3.html#fixers

Il encapsule également les utilisations existantes de dict.items (), dict.keys () et dict.values ​​() dans un appel à la liste.

Pourquoi est-ce nécessaire?

42
Dewfy

Vous pouvez ignorer cet avertissement "précautions supplémentaires" en toute sécurité: votre code fonctionnera de la même manière même sans list dans les deux versions de Python. Il fonctionnerait différemment si vous aviez besoin d'une liste (mais ce n'est pas le cas): en fait, features.items() est une liste dans Python 2, mais un view en Python 3. Ils fonctionnent de la même manière lorsqu'ils sont utilisés comme un itérable, comme dans votre exemple.

Maintenant, l'outil de conversion Python 2 en Python 3 2to3 Se trompe du côté de la sécurité et suppose que vous vouliez vraiment une liste lorsque vous utilisez dict.items(). Ce n'est peut-être pas le cas (comme dans la question), auquel cas dict.items() en Python 3 (pas de wrapping list) est meilleur (plus rapide et moins gourmand en mémoire, car aucune liste est construit).

Concrètement, cela signifie que le code Python 2 peut explicitement parcourir la vue: for k, v in features.viewitems() (qui sera convertie en Python 3 par 2to3 En features.items()). Il ressemble à votre IDE pense que le code est Python 2, car votre instruction for est très bonne, en Python 3, donc il ne devrait pas y avoir d'avertissement sur le support de Python 3.

41
Eric O Lebigot

Dans Python 2, les méthodes items(), keys() et values() permettent de "prendre un instantané" du contenu du dictionnaire et renvoyez-le sous forme de liste. Cela signifiait que si le dictionnaire changeait pendant que vous parcouriez la liste, le contenu de la liste ne changerait pas .

Dans Python 3, ces méthodes renvoient un objet de vue dont le contenu change dynamiquement à mesure que le dictionnaire change Par conséquent, pour que le comportement des itérations sur le résultat de ces méthodes reste cohérent avec les versions précédentes, un appel supplémentaire à list() doit être effectué dans Python = 3 pour "prendre un instantané" du contenu de l'objet de vue.

30
Frédéric Hamidi

Python 3 renvoie un Dictionary View Object plutôt qu'une liste qui Python 2 retournerait et certains opérateurs que vous attendez peuvent ne pas être vrais - un objet View changera également si le dictionnaire sous-jacent change, (éventuellement dans le code que vous parcourez, ce qui pourrait provoquer des surprises indésirables).

6
Steve Barnes

Dans Python 3, dict.items(), dict.keys() et dict.values() sont des itérateurs. Par conséquent, si vous attendez une liste, vous pouvez obtenir des erreurs lorsque vous effectuez des opérations qui fonctionnent sur des listes, mais pas nécessairement sur des itérateurs, comme len(dict.items()) (générera un TypeError).

CORRECTION

Le dict_items Renvoyé en appelant dict.items() dans Python 3 a en effet un __len__() et ne sera pas génère un TypeError. L'objet dict_items n'est cependant pas une liste et n'a pas de méthodes list, comme append(), index(), etc ...

En outre, comme les autres réponses (je dirais bien mieux) de Hamidi et Barnes, dict_items Est un objet de vue qui changera dynamiquement lorsque le dict sera modifié.

2
Joel Cornett

Lors de la conversion d'un projet en python 3 en utilisant 2to3, Vous pouvez désactiver cela en excluant le fixateur dict pour une sortie plus concise:

$ 2to3 -x dict *

Attention à iteritems(), iterkeys()https://docs.python.org/2/library/2to3.html#2to3fixer-dict et réparez à la main .

0
F. Malina