web-dev-qa-db-fra.com

Que sont les objets de la vue dictionnaire?

Dans python 2.7, nous avons le méthodes d'affichage du dictionnaire disponible.

Maintenant, je connais les avantages et les inconvénients des éléments suivants:

  • dict.items() (et values, keys): renvoie une liste pour que vous puissiez réellement stocker le résultat, et
  • dict.iteritems() (et autres): renvoie un générateur, ce qui vous permet de parcourir chaque valeur générée une par une.

À quoi servent dict.viewitems() (et autres)? Quels sont leurs avantages? Comment ça marche? Qu'est-ce qu'une vue après tout?

J'ai lu que la vue reflète toujours les modifications apportées par le dictionnaire. Mais comment se comporte-t-il du point de vue des performances et de la mémoire? Quels sont les avantages et les inconvénients?

145
e-satis

Les vues de dictionnaire sont essentiellement ce que leur nom indique: les vues sont simplement comme une fenêtre sur les clés et les valeurs (ou les éléments) d'un dictionnaire. Voici un extrait de la documentation officielle pour Python 3:

>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()

>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> keys  # No eggs anymore!
dict_keys(['sausage', 'bacon', 'spam'])

>>> values  # No eggs value (2) anymore!
dict_values([1, 1, 500])

(L’équivalent Python 2 utilise dishes.viewkeys() et dishes.viewvalues().)

Cet exemple montre le caractère dynamique des vues : la vue des clés est pas une copie des clés en un point donné dans le temps, mais plutôt une simple fenêtre qui vous montre les clés; si elles sont modifiées, ce que vous voyez à travers la fenêtre change également. Cette fonctionnalité peut être utile dans certaines circonstances (par exemple, vous pouvez utiliser une vue des clés dans plusieurs parties d'un programme au lieu de recalculer la liste actuelle des clés chaque fois que vous en avez besoin) - notez que si les clés du dictionnaire sont modifiées En itérant sur la vue, le comportement de l’itérateur n’est pas bien défini, ce qui peut entraîner des erreurs .

L’un des avantages est que look les touches, par exemple, utilisent seulement une petite quantité de mémoire fixe et nécessitent une petite quantité de temps processeur fixe , car il n’a pas été créé de liste de clés (Python 2, par contre, crée souvent inutilement une nouvelle liste, comme cité par Rajendran T, qui prend de la mémoire et du temps dans une quantité proportionnelle à la longueur de la liste). Pour continuer l'analogie de la fenêtre, si vous voulez voir un paysage derrière un mur, vous faites simplement une ouverture dans celui-ci (vous construisez une fenêtre); copier les clés dans une liste correspondrait à peindre une copie du paysage sur votre mur - la copie prend du temps, de l'espace et ne se met pas à jour.

Pour résumer, les vues sont simplement… des vues (fenêtres) de votre dictionnaire, qui montrent le contenu du dictionnaire même après qu'il ait été modifié. Ils offrent des fonctionnalités différentes de celles des listes: une liste de clés contient un copie des clés du dictionnaire à un moment donné, tandis qu'une vue est dynamique et beaucoup plus rapide à obtenir, comme il n'est pas nécessaire de copier des données (clés ou valeurs) pour être créé.

145
Eric O Lebigot

Comme vous l'avez mentionné, dict.items() renvoie une copie de la liste des paires (clé, valeur) du dictionnaire qui est inutile et dict.iteritems() renvoie un itérateur sur les paires (clé, valeur) du dictionnaire.

Maintenant, prenons l'exemple suivant pour voir la différence entre un interator de dict et une vue de dict

>>> d = {"x":5, "y":3}
>>> iter = d.iteritems()
>>> del d["x"]
>>> for i in iter: print i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Alors qu'une vue vous montre simplement ce qu'il y a dans le dict. Peu importe si cela a changé:

>>> d = {"x":5, "y":3}
>>> v = d.viewitems()
>>> v
dict_items([('y', 3), ('x', 5)])
>>> del d["x"]
>>> v
dict_items([('y', 3)])

Une vue est simplement ce à quoi le dictionnaire ressemble maintenant. Après avoir supprimé une entrée, .items() aurait été obsolète et .iteritems() aurait généré une erreur.

20
Martin Konecny

Les méthodes de vue renvoient une liste (et non une copie de la liste, par rapport à .keys(), .items() et .values()); elle est donc plus légère, mais reflète le contenu actuel du dictionnaire.

De Python 3.0 - les méthodes dict renvoient des vues - pourquoi?

La raison principale en est que, dans de nombreux cas d'utilisation, renvoyer une liste complètement séparée est inutile et inutile. Il faudrait copier tout le contenu (ce qui peut être peu ou pas).

Si vous voulez simplement parcourir les clés, il n'est pas nécessaire de créer une nouvelle liste. Et si vous en avez réellement besoin sous forme de liste séparée (en tant que copie), vous pouvez facilement créer cette liste à partir de la vue.

16
Rajendran T

En lisant la documentation, j'ai cette impression:

  1. Les vues ressemblent à des "pseudo-ensembles", en ce sens qu'elles ne prennent pas en charge l'indexation. Vous pouvez donc en faire un test d'adhésion et une itération sur elles (car les clés sont simples et uniques, les vues des clés et des éléments sont plus " set-like "en ce sens qu'ils ne contiennent pas de doublons).
  2. Vous pouvez les stocker et les utiliser plusieurs fois, comme les versions de liste.
  3. Parce qu'ils reflètent le dictionnaire sous-jacent, tout changement dans le dictionnaire changera la vue et changera presque certainement l'ordre des itérations. Donc, contrairement aux versions de liste, elles ne sont pas "stables".
  4. Parce qu'ils reflètent le dictionnaire sous-jacent, ce sont presque certainement de petits objets proxy; copier les clés/valeurs/éléments nécessiterait qu'ils observent le dictionnaire original d'une manière ou d'une autre et le copient plusieurs fois lorsque des modifications se produisent, ce qui constituerait une implémentation absurde. Donc, je m'attendrais à très peu de surcharge de mémoire, mais l'accès sera un peu plus lent que directement dans le dictionnaire.

Donc, je suppose que le cas d'utilisation clé est si vous gardez un dictionnaire et que vous le parcourez de manière répétée sur ses clés/éléments/valeurs avec des modifications entre les deux. Vous pouvez simplement utiliser une vue à la place, en transformant for k, v in mydict.iteritems(): en for k, v in myview:. Mais si vous parcourez simplement le dictionnaire une fois, je pense que les versions iter sont encore préférables.

16
Ben

Les vues vous permettent d'accéder à la structure de données sous-jacente sans la copier. Outre le fait d'être dynamique plutôt que de créer une liste, son utilisation la plus utile est in test. Dites que vous voulez vérifier si une valeur est dans le dict ou non (que ce soit la clé ou la valeur).

La première option est de créer une liste de clés en utilisant dict.keys(), cela fonctionne mais consomme évidemment plus de mémoire. Si le dict est très gros? Ce serait un gaspillage.

Avec views, vous pouvez itérer la structure de données réelle, sans liste intermédiaire.

Utilisons des exemples. J'ai un dict avec 1000 clés de chaînes et de chiffres aléatoires et k est la clé que je veux rechercher

large_d = { .. 'NBBDC': '0RMLH', 'E01AS': 'UAZIQ', 'G0SSL': '6117Y', 'LYBZ7': 'VC8JQ' .. }

>>> len(large_d)
1000

# this is one option; It creates the keys() list every time, it's here just for the example
timeit.timeit('k in large_d.keys()', setup='from __main__ import large_d, k', number=1000000)
13.748743600954867


# now let's create the list first; only then check for containment
>>> list_keys = large_d.keys()
>>> timeit.timeit('k in list_keys', setup='from __main__ import large_d, k, list_keys', number=1000000)
8.874809793833492


# this saves us ~5 seconds. Great!
# let's try the views now
>>> timeit.timeit('k in large_d.viewkeys()', setup='from __main__ import large_d, k', number=1000000)
0.08828549011070663

# How about saving another 8.5 seconds?

Comme vous pouvez le constater, l'itération de l'objet view améliore considérablement les performances tout en réduisant la surcharge de mémoire. Vous devriez les utiliser lorsque vous devez effectuer des opérations comme Set.

Note: Je tourne sous Python 2.7

5
Chen A.