Recherche de site Web

Compréhensions du dictionnaire Python : comment et quand les utiliser


Les compréhensions de dictionnaires constituent un moyen concis et rapide de créer, transformer et filtrer des dictionnaires en Python. Ils peuvent améliorer considérablement la concision et la lisibilité de votre code par rapport à l'utilisation de boucles for classiques pour traiter vos dictionnaires.

Comprendre les compréhensions de dictionnaires est crucial pour vous en tant que développeur Python, car il s'agit d'un outil Pythonique pour la manipulation de dictionnaires et peut constituer un ajout précieux à votre boîte à outils de programmation.

Dans ce didacticiel, vous apprendrez à :

  • Créer des dictionnaires à l'aide des compréhensions de dictionnaires
  • Transformer les dictionnaires existants avec des compréhensions
  • Filtrer les paires clé-valeur des dictionnaires à l'aide de conditions
  • Décider quand utiliser les compréhensions du dictionnaire

Pour tirer le meilleur parti de ce didacticiel, vous devez être familier avec les concepts de base de Python, tels que les boucles for, les itérables et les dictionnaires, ainsi que la compréhension des listes.

Créer et transformer des dictionnaires en Python

En programmation Python, vous devrez souvent créer, remplir et transformer des dictionnaires. Pour ce faire, vous pouvez utiliser des littéraux de dictionnaire, le constructeur dict() et les boucles for. Dans les sections suivantes, vous découvrirez rapidement comment utiliser ces outils. Vous découvrirez également les compréhensions de dictionnaires, qui constituent un moyen puissant de manipuler les dictionnaires en Python.

Création de dictionnaires avec des littéraux et dict()

Pour créer de nouveaux dictionnaires, vous pouvez utiliser des littéraux. Un littéral de dictionnaire est une série de paires clé-valeur entourées d’accolades. La syntaxe d'un littéral de dictionnaire est présentée ci-dessous :

{key_1: value_1, key_2: value_2,..., key_N: value_N}

Les clés doivent être des objets hachables et sont généralement des chaînes. Les valeurs peuvent être n'importe quel objet Python, y compris d'autres dictionnaires. Voici un exemple rapide de dictionnaire :

>>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
>>> likes
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

>>> likes["hobby"] = "guitar"
>>> likes
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog', 'hobby': 'guitar'}

Dans cet exemple, vous créez des paires clé-valeur de dictionnaire qui décrivent des choses que les gens aiment souvent. Les clés et valeurs de votre dictionnaire sont des objets chaîne. Vous pouvez ajouter de nouvelles paires au dictionnaire en utilisant la syntaxe dict[key]=value.

Vous pouvez également créer de nouveaux dictionnaires en utilisant le constructeur dict() :

>>> dict(apple=0.40, orange=0.35, banana=0.25)
{'apple': 0.4, 'orange': 0.35, 'banana': 0.25}

Dans cet exemple, vous créez un nouveau dictionnaire en utilisant dict() avec des arguments de mots-clés. Dans ce cas, les clés sont des chaînes et les valeurs sont des nombres à virgule flottante. Il est important de noter que le constructeur dict() ne convient que dans les cas où les clés du dictionnaire peuvent être des chaînes qui sont des identifiants Python valides.

Utilisation des boucles for pour remplir les dictionnaires

Parfois, vous devez commencer avec un dictionnaire vide et le remplir dynamiquement avec des paires clé-valeur. Pour ce faire, vous pouvez utiliser une boucle for. Par exemple, supposons que vous souhaitiez créer un dictionnaire dans lequel les clés sont des nombres entiers et les valeurs sont des puissances de 2.

Voici comment procéder avec une boucle for :

>>> powers_of_two = {}

>>> for integer in range(1, 10):
...     powers_of_two[integer] = 2**integer
...

>>> powers_of_two
{1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64, 7: 128, 8: 256, 9: 512}

Dans cet exemple, vous créez un dictionnaire vide à l’aide d’une paire d’accolades vides. Ensuite, vous exécutez une boucle sur une plage de nombres entiers allant de 1 à 9. À l’intérieur de la boucle, vous remplissez le dictionnaire avec les nombres entiers comme clés et les puissances de deux comme valeurs.

La boucle dans cet exemple est lisible et claire. Cependant, vous pouvez également utiliser la compréhension de dictionnaire pour créer et remplir un dictionnaire comme celui présenté ci-dessus.

Présentation des compréhensions de dictionnaires

Les compréhensions de dictionnaire vous permettent de créer des dictionnaires avec une boucle for sur une seule ligne. Si vous êtes familier avec la compréhension de listes, vous maîtriserez rapidement la compréhension de dictionnaire. Les deux constructions ont une syntaxe similaire. La principale différence est que les compréhensions du dictionnaire utilisent des accolades au lieu de crochets. De plus, l’expression de compréhension doit inclure une clé et une valeur séparées par deux points.

Voici la syntaxe pour une compréhension du dictionnaire :

{key: value for member in iterable [if condition]}

Une compréhension de dictionnaire renvoie un nouveau dictionnaire. Pour créer ce dictionnaire, vous calculez les paires clé-valeur à partir des éléments d'un itérable d'entrée. Notez que la syntaxe inclut un conditionnel facultatif à la fin, que vous pouvez utiliser pour filtrer les dictionnaires existants.

La syntaxe de compréhension comprend quatre éléments :

  1. Parenthèses : Les accolades ({}) sont utilisées pour la compréhension du dictionnaire.
  2. L'expression de compréhension : une expression qui fournit une valeur à chaque itération. En compréhension du dictionnaire, l'expression doit fournir la clé et sa valeur correspondante, key: value. Les deux éléments peuvent être des expressions.
  3. Le membre actuel : Il s'agit de l'élément ou de la valeur actuelle dans l'itérable.
  4. Le itérable : Il peut s'agir de n'importe quel objet itérable Python, y compris une liste, un tuple, un ensemble, un générateur ou similaire.

Le code suivant montre comment créer le dictionnaire power_of_two à l'aide d'une compréhension :

>>> power_of_two = {integer: 2**integer for integer in range(1, 10)}

>>> power_of_two
{1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64, 7: 128, 8: 256, 9: 512}

Dans cet exemple, integer : 2**integer est l'expression de compréhension, integer est le membre actuel et range(1, 10) est l'itérable.

Voici un diagramme qui illustre le processus de conversion de votre boucle de la section précédente en compréhension de dictionnaire équivalente :

Comme vous pouvez le constater, avec quelques mouvements et l’ajout des accolades englobantes, votre compréhension est complète.

Les compréhensions peuvent également avoir plusieurs clauses for. Lorsqu'ils le font, le for le plus à gauche parcourt la collection externe, le for suivant de gauche à droite parcourt le premier niveau d'imbrication, et ainsi de suite.

Pour illustrer, disons que vous avez une liste de listes. Chaque liste imbriquée contient des nombres. Vous souhaitez créer un dictionnaire qui mappe les nombres à leurs valeurs carrées. Vous pouvez utiliser une compréhension avec deux clauses for comme indiqué ci-dessous :

>>> matrix = [
...     [9, 3, 8, 3],
...     [4, 5, 2, 8],
...     [6, 4, 3, 1],
...     [1, 0, 4, 5],
... ]

>>> {value: value**2 for row in matrix for value in row}
{9: 81, 3: 9, 8: 64, 4: 16, 5: 25, 2: 4, 6: 36, 1: 1, 0: 0}

Dans cet exemple, la première boucle for parcourt les lignes de votre matrice. La deuxième boucle for parcourt le numéro de chaque ligne. En conséquence, vous obtenez un dictionnaire qui mappe les nombres à leurs valeurs carrées. Même si cette syntaxe fonctionne, elle peut rendre votre compréhension difficile à lire et à comprendre.

Il est important de noter que dans cet exemple, au lieu d’avoir 16 paires clé-valeur, vous n’en avez que neuf. En effet, les clés du dictionnaire sont uniques. Lorsque la clé est dupliquée, la nouvelle valeur remplace la précédente. Dans cet exemple, ce comportement ne pose pas de problème car les valeurs seront toujours le carré de leurs clés correspondantes.

Tirer parti des compréhensions de dictionnaires en Python

Grâce aux compréhensions de dictionnaires, vous pouvez créer de nouveaux dictionnaires, transformer ceux existants et même filtrer les paires clé-valeur. Dans les sections suivantes, vous apprendrez à utiliser la compréhension du dictionnaire pour aborder tous ces cas d'utilisation. Pour commencer, vous commencerez par apprendre à créer de nouveaux dictionnaires à partir d’itérables existants.

Création de dictionnaires à partir d'itérables

Parfois, vous disposez d'un itérable de données et souhaitez créer un dictionnaire en utilisant les éléments de données pour générer les clés et les valeurs, tout en appliquant également une certaine transformation aux données d'origine. Pour un exemple rapide, disons que vous avez une liste de fruits et que vous souhaitez créer un dictionnaire où les clés sont les noms de fruits affichés en majuscules et les valeurs représentent le nombre de lettres dans chaque nom :

>>> fruits = ["apple", "banana", "cherry"]

>>> {fruit.upper(): len(fruit) for fruit in fruits}
{'APPLE': 5, 'BANANA': 6, 'CHERRY': 6}

Dans cet exemple, vous appliquez des transformations pour générer les clés et les valeurs. Dans la programmation réelle, vous devrez souvent appliquer des transformations pour générer les valeurs ou les clés.

Prenons l'exemple suivant qui crée un dictionnaire avec des lettres minuscules comme clés et leurs points de code Unicode comme valeurs :

>>> from string import ascii_lowercase

>>> {letter: ord(letter) for letter in ascii_lowercase}
{
    'a': 97,
    'b': 98,
    'c': 99,
    'd': 100,
    'e': 101,
    ...
    'z': 122,
}

Dans cet exemple, vous générez les valeurs du dictionnaire en exécutant une transformation sur les éléments fournis. Vous utilisez les éléments de données directement pour fournir les clés.

Parfois, vous disposez de deux séquences de données et souhaitez mapper chaque élément de la première séquence à l’élément correspondant de la seconde. Dans ce cas, vous pouvez utiliser le code suivant :

>>> parts = [
...     "CPU",
...     "GPU",
...     "Motherboard",
...     "RAM",
...     "SSD",
...     "Power Supply",
...     "Case",
...     "Cooling Fan"
... ]

>>> stocks = [15, 8, 12, 30, 25, 10, 5, 20]

>>> {part: stock for part, stock in zip(parts, stocks)}
{
    'CPU': 15,
    'GPU': 8,
    'Motherboard': 12,
    'RAM': 30,
    'SSD': 25,
    'Power Supply': 10,
    'Case': 5,
    'Cooling Fan': 20
}

Dans cet exemple, vous utilisez la fonction intégrée zip() pour créer des paires d'éléments. Cette fonction prend au moins deux itérables comme arguments et génère des tuples d'éléments en obtenant un élément de chaque itérable.

En pratique, lorsque vous devez créer un dictionnaire à partir de deux séquences sans appliquer aucune transformation sur les données, vous pouvez utiliser le code suivant à la place d'une compréhension :

>>> dict(zip(parts, stocks))
{
    'CPU': 15,
    'GPU': 8,
    'Motherboard': 12,
    'RAM': 30,
    'SSD': 25,
    'Power Supply': 10,
    'Case': 5,
    'Cooling Fan': 20
}

Cette façon de créer un dictionnaire à partir de deux séquences est assez pythonique et simple. Vous n’avez pas besoin de compréhension. Cependant, si vous devez transformer les données d’une manière ou d’une autre, vous bénéficierez alors d’une compréhension.

Par exemple, disons que vous disposez d’une troisième liste contenant les prix de chaque pièce d’ordinateur. Vous souhaitez créer un dictionnaire contenant les pièces sous forme de clés et leurs coûts sous forme de valeurs. Dans cette situation, vous ne pouvez pas utiliser l’astuce ci-dessus. Vous devez utiliser une compréhension :

>>> part_costs = [250, 500, 150, 80, 100, 120, 70, 25]

>>> {
...     part: stock * cost
...     for part, stock, cost in zip(parts, stocks, part_costs)
... }
{
    'CPU': 3750,
    'GPU': 4000,
    'Motherboard': 1800,
    'RAM': 2400,
    'SSD': 2500,
    'Power Supply': 1200,
    'Case': 350,
    'Cooling Fan': 500,
}

Dans cet exemple, l'utilisation de zip() combinée avec dict() ne fournit pas une solution appropriée pour construire le dictionnaire car vous devez calculer les valeurs. C’est alors qu’une compréhension s’avère utile, car elle permet de gérer le calcul des valeurs.

Transformer les dictionnaires existants

Vous pouvez également utiliser des compréhensions pour transformer les clés ou les valeurs de dictionnaires existants. Un exemple typique est lorsque vous devez échanger des clés et des valeurs.

Par exemple, supposons que vous disposiez d'un dictionnaire contenant des composants informatiques correspondant à des codes de composants et que vous souhaitiez une configuration opposée. Dans cette situation, vous pouvez utiliser une compréhension de dictionnaire pour échanger les clés et les valeurs :

>>> parts = {
...     "CPU": 10021,
...     "GPU": 10022,
...     "Motherboard": 10023,
...     "RAM": 10024,
...     "SSD": 10025,
...     "Power Supply": 10027,
...     "Case": 10026,
...     "Cooling Fan": 10025,
... }

>>> {value: key for key, value in parts.items()}
{
    10021: 'CPU',
    10022: 'GPU',
    10023: 'Motherboard',
    10024: 'RAM',
    10025: 'Cooling Fan',
    10027: 'Power Supply',
    10026: 'Case'
}

Dans cette compréhension, vous utilisez la méthode .items() sur le dictionnaire parts pour accéder aux paires clé-valeur. Ensuite, vous disposez de deux variables de boucle, une pour les clés et une pour les valeurs. Dans l'expression de compréhension, vous échangez les clés et les valeurs.

Vous pouvez obtenir le même résultat en utilisant le code suivant qui combine dict() et zip() avec .values() et Méthodes du dictionnaire .keys() :

>>> dict(zip(parts.values(), parts.keys()))
{
    10021: 'CPU',
    10022: 'GPU',
    10023: 'Motherboard',
    10024: 'RAM',
    10025: 'Cooling Fan',
    10027: 'Power Supply',
    10026: 'Case'
}

Dans cet exemple, vous utilisez une combinaison d’appels de fonction et de méthode au lieu d’une compréhension. Le résultat est le même qu’avec une compréhension.

Comme autre exemple, disons que vous disposez d'un dictionnaire des fruits et de leurs prix, et que vous devez diminuer les prix de 5 %. Vous pouvez le faire avec une compréhension :

>>> fruits = {
...     "apple": 1.00,
...     "banana": 0.50,
...     "cherry": 2.00,
... }

>>> {fruit: round(price * 0.95, 2) for fruit, price in fruits.items()}
{'apple': 0.95, 'banana': 0.48, 'cherry': 1.90}

Dans cet exemple, vous transformez les valeurs du dictionnaire d'origine. Vous disposez désormais d’un nouveau dictionnaire avec des prix inférieurs de 5 %.

Vous pouvez appliquer la transformation uniquement aux clés, ou aux valeurs et aux clés, selon vos besoins.

Filtrage des éléments des dictionnaires

Les compréhensions de dictionnaires vous permettent également d'utiliser un conditionnel à la fin de leur syntaxe. Ce conditionnel vous permettra de créer des dictionnaires en filtrant les données existantes. Vous pouvez utiliser la syntaxe conditionnelle avec des clés et des valeurs.

Voici un exemple qui filtre un dictionnaire de nombres en fonction de leurs valeurs pour créer un dictionnaire de nombres pairs :

>>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}

>>> {key: value for key, value in numbers.items() if value % 2 == 0}
{'two': 2, 'four': 4}

Le conditionnel à la fin de la compréhension filtre les nombres impairs du dictionnaire original. En conséquence, vous obtenez un dictionnaire de nombres pairs.

Pour savoir comment filtrer un dictionnaire par clés, supposons que vous disposez d'un dictionnaire qui mappe les codes postaux aux villes et que vous devez filtrer le dictionnaire pour obtenir les villes dans une plage de codes postaux :

>>> codes = {
...     "1001": "Townsville",
...     "1002": "Lakeview",
...     "1003": "Mountainview",
...     "1101": "Riverside",
...     "1102": "Hilltop",
...     "1201": "Greenfield",
...     "1202": "Sunnydale",
...     "1301": "Meadowbrook",
...     "1302": "Creekwood"
... }

>>> {code: town for code, town in codes.items() if "1100" <= code <= "1300"}
{
    '1101': 'Riverside',
    '1102': 'Hilltop',
    '1201': 'Greenfield',
    '1202': 'Sunnydale'
}

Dans cet exemple, la condition vérifie si le code postal actuel est compris entre 1 100 et 1 300. Cette condition filtre le dictionnaire d'origine et en génère un nouveau avec les villes dans la plage de codes cible.

Décider quand utiliser les compréhensions de dictionnaire

Lorsque vous décidez d'utiliser une compréhension de dictionnaire au lieu de boucles régulières ou d'une combinaison d'appels de fonction, vous devez prendre en compte les facteurs suivants :

  • Concision : les compréhensions de dictionnaire réduisent la quantité de code par rapport aux boucles for équivalentes.
  • Lisibilité : la compréhension du dictionnaire peut rendre votre code plus explicite et plus lisible.

En pratique, vous pouvez utiliser les compréhensions de dictionnaire lorsque vous devez effectuer certaines des opérations suivantes :

  • Créer un dictionnaire à partir d'un itérable existant
  • Fusionner les itérables dans un dictionnaire tout en transformant les clés, les valeurs ou les deux
  • Transformer les clés et les valeurs du dictionnaire, ou les deux
  • Filtrer un dictionnaire existant

Jusqu’à présent, vous avez appris à effectuer toutes ces opérations en utilisant la compréhension du dictionnaire. Néanmoins, vous pouvez trouver d'autres bons cas d'utilisation pour la compréhension de dictionnaires au cours de votre expérience de codage Python.

Enfin, il existe des situations dans lesquelles vous souhaitez éviter les compréhensions du dictionnaire. Par exemple, lorsque vous souhaitez traiter un grand ensemble de données pour produire des paires clé-valeur. Utiliser la compréhension du dictionnaire dans cette situation créera un dictionnaire volumineux et le stockera en mémoire, ce qui entraînera une consommation de mémoire élevée.

Pour rendre votre code efficace en termes de mémoire, vous pouvez utiliser une expression génératrice qui génère des tuples de la forme (clé, valeur) :

>>> squares_generator = ((x, x * x) for x in range(1_000_000))
>>> squares_generator
<generator object <genexpr> at 0x106e2ac20>

>>> next(squares_generator)
(0, 0)
>>> next(squares_generator)
(1, 1)
>>> next(squares_generator)
(2, 4)
>>> next(squares_generator)
(3, 9)

Dans cet exemple, vous utilisez une expression génératrice pour créer un itérateur qui génère des tuples de deux valeurs. La première valeur est un nombre et la seconde est sa valeur carrée.

L'itérateur résultant génère des tuples à la demande, ce qui signifie que vous n'utiliserez la mémoire que pour stocker un tuple à la fois. Vous n’avez pas besoin de stocker un dictionnaire d’un million de paires clé-valeur dans la mémoire de votre ordinateur, et éviter cela rendra votre code plus efficace.

Au lieu de cela, vous pouvez utiliser la fonction intégrée next() pour parcourir l'itérateur résultant, ou vous pouvez utiliser une boucle for.

Explorer les mauvaises pratiques courantes

Vous devez éviter quelques mauvaises pratiques lorsque vous travaillez avec des compréhensions de dictionnaire dans votre code Python. Certains des plus courants sont les suivants :

  • Utiliser des expressions complexes dans les compréhensions
  • Écrire des compréhensions imbriquées avec plusieurs clauses for ou plusieurs conditions
  • Exécuter des transformations coûteuses tout en créant les clés et les valeurs
  • Essayer d'accéder aux variables de compréhension de l'extérieur

Parfois, vous pouvez vous retrouver avec une compréhension du dictionnaire où l'expression de compréhension est trop compliquée. Par exemple, vous souhaiterez peut-être appliquer des transformations de manière conditionnelle et penser à quelque chose comme ce qui suit :

>>> fruits = {"apple": 1.0, "banana": 0.5, "cherry": 2.0, "mango": 2.3}
>>> with_discount = ["apple", "cherry"]

>>> {
...     fruit: price * 0.9 if fruit in with_discount else price
...     for fruit, price in fruits.items()
... }
{'apple': 0.9, 'banana': 0.5, 'cherry': 1.8, 'mango': 2.3}

Dans cette compréhension, vous appliquez une remise de prix à une liste de fruits sélectionnés. Pour ce faire, vous utilisez une expression conditionnelle comme expression de compréhension. Vous trouverez peut-être difficile de lire cette compréhension et de déchiffrer ce qu'elle fait. Lorsqu'une expression compliquée rend votre code difficile à lire, vous pouvez plutôt bénéficier d'une boucle for régulière pour rendre votre code plus lisible.

Les compréhensions imbriquées avec plusieurs clauses for ou conditions peuvent rendre votre code moins lisible. Donc, en général, vous devriez les éviter et utiliser des constructions plus lisibles comme une boucle normale.

Essayer d’utiliser les variables que vous définissez dans une compréhension en dehors de la compréhension elle-même n’est pas possible :

>>> {value: value**3 for value in range(1, 11)}
{
    1: 1,
    2: 8,
    3: 27,
    4: 64,
    5: 125,
    6: 216,
    7: 343,
    8: 512,
    9: 729,
    10: 1000
}

>>> value
Traceback (most recent call last):
    ...
NameError: name 'value' is not defined

La variable value n'est visible qu'en compréhension. Si vous essayez de l'utiliser en dehors de la compréhension, vous obtenez une NameError.

Parfois, lorsque vous travaillez avec des compréhensions de dictionnaires, vous devrez peut-être exécuter des transformations de données coûteuses pour générer des clés, des valeurs ou les deux. Dans ces situations, vous devez être conscient que la création du dictionnaire final en mémoire peut prendre un temps considérable. Une solution de contournement possible consiste à utiliser un générateur qui produit les paires clé-valeur à la demande.

Conclusion

Vous avez découvert en détail la compréhension du dictionnaire Python. Il s'agit d'un outil puissant pour créer, transformer et filtrer des dictionnaires en utilisant une syntaxe concise et claire. Vous avez également découvert certaines mauvaises pratiques et pièges que vous devriez éviter lorsque vous travaillez avec des compréhensions de dictionnaires.

Les compréhensions de dictionnaires sont une excellente ressource pour les développeurs Python, fournissant un moyen pythonique et rationalisé de manipuler les dictionnaires, qui sont des structures de données fondamentales en Python.

Dans ce didacticiel, vous avez :

  • Création de nouveaux dictionnaires avec une syntaxe concise
  • Transformation des dictionnaires existants avec des compréhensions
  • Filtré les paires clé-valeur indésirables à partir des dictionnaires
  • Décidé quand utiliser les compréhensions dans votre code

Avec ces compétences, vous pouvez écrire du code Pythonique plus lisible pour traiter les dictionnaires. Au fur et à mesure que vous continuez à utiliser les compréhensions de dictionnaires, vous constaterez qu’elles constituent un outil inestimable.