ProgrammationDéveloppeur Python

Expliquez comment fonctionnent les arguments *args et **kwargs dans les fonctions Python. À quoi servent-ils, quels dangers présentent-ils en cas de mauvaise utilisation et comment les combiner correctement avec des arguments normaux et des arguments nommés ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

*args — recueille un nombre arbitraire d'arguments positionnels dans un tuple.

**kwargs — recueille un nombre arbitraire d'arguments nommés (clé=valeur) dans un dictionnaire.

Cela permet d'écrire des fonctions avec une interface flexible :

def my_func(a, b, *args, **kwargs): print(a, b) print(args) print(kwargs) my_func(1, 2, 3, 4, x=10, y=20) # 1 2 # (3, 4) # {'x': 10, 'y': 20}

Les subtilités :

  • Les arguments normaux viennent en premier, suivis de *args, puis des nommés avec des valeurs par défaut, et enfin **kwargs — strictement dans cet ordre lors de la déclaration de la fonction.
  • On peut "déballer" des séquences avec * et des dictionnaires avec ** lors de l'appel de la fonction.
  • Il est impossible de redéfinir les mêmes paramètres — cela entraînera une erreur TypeError.

Question piège

Peut-on changer l'ordre de *args et des arguments nommés avec une valeur par défaut, par exemple :

def foo(a, *args, x=10, **kwargs): pass

ou faut-il toujours placer les valeurs par défaut après *args ?

Réponse :

Dans Python 3, c'est possible ! Comme ça (cela ne fonctionnait pas dans Python 2) :

def foo(a, *args, x=10): pass

Les paramètres après *args ("arguments uniquement par mot-clé") peuvent avoir des valeurs par défaut ou être obligatoires — ils ne peuvent être définis que par nom.

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


Histoire

Transmission d'arguments incorrects via *args/**kwargs

Dans les services REST API, l'automatisation du marshaling des données était construite via **kwargs. Un paramètre superflu n'a pas été remarqué — la fonction prenait une valeur inattendue dans kwargs, ce qui entraînait une perte de logique de contrôle et des bugs difficiles à déboguer.


Histoire

Duplication d'arguments nommés

Lors de l'appel de la fonction, le développeur a accidentellement spécifié un paramètre à la fois de manière explicite et via **kwargs, par exemple : my_func(a=1, **{"a": 2}). En conséquence — TypeError et arrêt du service.


Histoire

Oubli d'arguments positionnels ou uniquement nommés

Lors de l'écriture d'un décorateur, une transmission incorrecte des paramètres (non respect de l'ordre et de la structure) conduisait à ce que la fonction originale reçoive un nombre incorrect d'arguments, des accords changeant, et des erreurs d'appel TypeError commençaient à apparaître en production.