ProgrammationDéveloppeur Python Fullstack

Expliquez le mécanisme de fonctionnement des opérateurs * et ** lors de la décompression des séquences et des dictionnaires en Python. Quels sont les points subtils et où cela peut-il être utile ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

Les opérateurs * et ** pour la décompression existent depuis longtemps dans Python, mais leur utilisation s'est étendue avec chaque version (par exemple, depuis Python 3.5, le support pour la fusion de plusieurs collections à travers * et ** a été ajouté). Ces opérateurs rendent le travail avec des collections plus flexible, notamment lors du passage d'arguments et de leur collecte dans des fonctions.

Problème :

Sans décompression, lors du travail avec des séquences dynamiques, le passage de paramètres avec un nombre variable d'arguments nécessite d'écrire manuellement des boucles et de vérifier la dimension des collections. Des erreurs peuvent survenir facilement en cas d'utilisation incorrecte ou si l'on ne distingue pas l'objectif de * et **.

Solution :

L'opérateur * est destiné à décompresser des séquences (liste, tuple, ensemble), tandis que l'opérateur ** est utilisé pour décompresser des dictionnaires lors de l'appel de fonctions ou de la fusion de plusieurs dictionnaires. Ils permettent de passer des arguments élégamment, de fusionner des collections, et de transformer facilement des structures arbitraires en paramètres de fonction.

Exemple de code :

def foo(a, b, c): print(a, b, c) args = (1, 2, 3) foo(*args) # 1 2 3 params = {'a': 10, 'b': 20, 'c': 30} foo(**params) # 10 20 30 list1 = [1, 2] list2 = [3, 4] combined = [*list1, *list2] print(combined) # [1, 2, 3, 4]

Caractéristiques clés :

  • *sequence transmet les éléments comme des arguments positionnels distincts, **dict comme des arguments nommés.
  • On peut fusionner et copier des collections élégamment via [*a, *b] et {**d1, **d2}.
  • La décompression est appliquée à la fois lors de la définition/de la déclaration de fonctions et lors de leur appel.

Questions pièges.

Peut-on utiliser * et ** pour des collections mixtes ?

Lors de l'appel d'une fonction, * ne fonctionne qu'avec des arguments positionnels, tandis que ** ne fonctionne qu'avec des arguments nommés. Si un dictionnaire non décompressé est passé comme * ou une séquence comme **, une erreur se produira.

def foo(a, b): print(a, b) foo(*{'a': 1, 'b': 2}) # Affiche : a b (les clés du dictionnaire, pas les valeurs !)

**Que se passera-t-il si les noms des clés se chevauchent lors de la fusion de dictionnaires via {**d1, d2}?

En conséquence, la valeur du dernier dictionnaire avec cette clé sera conservée.

d1 = {'x': 1, 'y': 2} d2 = {'y': 33, 'z': 44} merged = {**d1, **d2} print(merged) # {'x': 1, 'y': 33, 'z': 44}

Peut-on utiliser * et ** à l'intérieur d'expressions de listes ou de dictionnaires ?

Oui, c'est légal depuis Python 3.5, par exemple :

lst = [1, 2, *range(3, 6)] # [1, 2, 3, 4, 5] dct = {**{'a': 1}, 'b': 2, **{'c': 3}}

Erreurs typiques et anti-patterns

  • Passer un dictionnaire via * (seules les clés seront décompressées).
  • Le chevauchement excessif des arguments nommés entraîne un TypeError.
  • Essayer d'utiliser ** pour un objet qui n'est pas un mapping.

Exemple de la vie réelle

Cas négatif

Un développeur passe un dictionnaire en entrée de fonction et l'analyse avec * au lieu de **. Cela entraîne un comportement inattendu : les clés entrent dans la fonction au lieu des valeurs.

Avantages :

Le code ne plante pas immédiatement, semble “fonctionnel”.

Inconvénients :

Erreurs cachées et incohérence par rapport à la logique attendue.

Cas positif

Passage correct des paramètres via **kwargs, fusion soigneuse des dictionnaires, utilisation de * lors de la fusion dynamique des séquences.

Avantages :

Flexibilité maximale, concision du code, simplicité de refactorisation.

Inconvénients :

Avec un grand nombre de paramètres et de collections, il est important de suivre les noms et l'ordre avec attention, sinon des erreurs peuvent survenir.