Python *args et **kwargs
Apprenez comment *args et **kwargs permettent aux fonctions Python d'accepter un nombre variable d'arguments positionnels et nommés, avec des exemples concrets.
*args et **kwargs sont une syntaxe spéciale de Python qui permet à une fonction d'accepter un nombre variable d'arguments. *args regroupe les arguments positionnels supplémentaires dans un tuple, tandis que **kwargs regroupe les arguments nommés supplémentaires dans un dictionnaire. Ensemble, ils vous offrent une flexibilité totale — vous pouvez écrire des fonctions qui fonctionnent avec un seul argument ou avec cent.
Cette page couvre les deux fonctionnalités en profondeur : leur fonctionnement, quand les utiliser, comment les combiner et les erreurs courantes à éviter.
Qu'est-ce que *args ?
Lorsque vous faites précéder un nom de paramètre d'un seul astérisque (*), Python regroupe tous les arguments positionnels supplémentaires passés à la fonction dans un tuple lié à ce nom de paramètre. Le nom args est une convention — vous pourriez écrire *numbers ou *values — mais *args est universellement compris.
def add_all(*args):
total = 0
for n in args:
total += n
return total
print(add_all(1, 2, 3)) # 6
print(add_all(10, 20, 30, 40)) # 100
print(add_all()) # 0À l'intérieur de la fonction, args est un tuple ordinaire que vous pouvez parcourir, indexer ou passer à d'autres fonctions. Appeler add_all() sans argument est valide — args est simplement un tuple vide.
Mélanger des paramètres ordinaires avec *args
Les paramètres ordinaires (positionnels) viennent en premier ; *args capture tout ce qui suit :
def greet(greeting, *names):
for name in names:
print(greeting + ', ' + name + '!')
greet('Hello', 'Alice', 'Bob', 'Charlie')
# Hello, Alice!
# Hello, Bob!
# Hello, Charlie!greeting est renseigné par le premier argument ; names reçoit le reste sous forme de tuple. Si vous appelez greet('Hi') sans noms supplémentaires, names est un tuple vide et la boucle ne s'exécute tout simplement pas — aucune erreur.
Qu'est-ce que **kwargs ?
Deux astérisques (**) placés avant un nom de paramètre indiquent à Python de regrouper tous les arguments nommés supplémentaires dans un dictionnaire. Là encore, kwargs est une convention ; tout identifiant Python valide convient.
def describe(**kwargs):
for key, value in kwargs.items():
print(key + ': ' + str(value))
describe(name='Alice', age=30, city='New York')
# name: Alice
# age: 30
# city: New YorkÀ l'intérieur de la fonction, kwargs est un dictionnaire ordinaire. Vous pouvez le parcourir, rechercher des clés ou le transmettre. L'appelant décide des clés à fournir — aucune n'est imposée par la définition de la fonction.
Quand utiliser **kwargs
**kwargs est particulièrement utile lorsque :
- Une fonction doit accepter un ensemble flexible et ouvert d'options nommées (configuration, métadonnées, attributs HTML).
- Vous écrivez un wrapper qui doit transmettre des arguments nommés à une autre fonction sans savoir ce qu'ils sont.
- Vous voulez construire un dictionnaire à partir d'arguments nommés de manière lisible (évite le code répétitif de
dict(key=value, ...)).
Combiner *args et **kwargs
Une seule fonction peut accepter un nombre illimité d'arguments positionnels et un nombre illimité d'arguments nommés. L'ordre requis dans la signature est le suivant :
- Paramètres positionnels normaux
*args- Paramètres uniquement nommés (avec valeurs par défaut)
**kwargs
def log_event(event, *tags, **metadata):
print('Event:', event)
print('Tags:', tags)
print('Metadata:', metadata)
log_event('login', 'auth', 'user', user_id=42, ip='127.0.0.1')
# Event: login
# Tags: ('auth', 'user')
# Metadata: {'user_id': 42, 'ip': '127.0.0.1'}event prend le premier argument positionnel ; tags capture les arguments positionnels restants ; metadata capture tous les arguments nommés.
Décomposer des arguments avec * et **
Les opérateurs * et ** ne servent pas uniquement dans les définitions de fonctions — ils fonctionnent également du côté de l'appel pour décomposer des séquences et des correspondances en arguments séparés.
Décomposer une liste ou un tuple avec *
def multiply(a, b, c):
return a * b * c
nums = [2, 3, 4]
print(multiply(*nums)) # 24*nums décompose la liste de sorte que a=2, b=3, c=4. C'est équivalent à écrire multiply(2, 3, 4). Voir Décomposer les tuples pour en savoir plus sur l'opérateur de décomposition.
Décomposer un dictionnaire avec **
def power(base, exp):
return base ** exp
params = {'base': 3, 'exp': 4}
print(power(**params)) # 81**params associe chaque clé du dictionnaire au nom de paramètre correspondant. Cela est utile lorsque les arguments sont stockés dans un dictionnaire de configuration construit à l'exécution.
Arguments uniquement nommés après *args
Tout paramètre listé après *args dans la signature ne peut être passé que par nom (il devient un argument uniquement nommé). C'est une façon élégante d'ajouter des indicateurs optionnels sans ambiguïté :
def configure(host, *args, port=80, debug=False):
print('host:', host)
print('extra:', args)
print('port:', port)
print('debug:', debug)
configure('localhost', 'arg1', port=8080, debug=True)
# host: localhost
# extra: ('arg1',)
# port: 8080
# debug: Trueport et debug ne peuvent pas être définis par position car *args consomme déjà tous les arguments positionnels supplémentaires. Ce modèle est courant dans les API de bibliothèques — les utilisateurs doivent écrire explicitement port=8080, ce qui rend les appels autodocumentés.
Pour une explication détaillée des règles de portée de Python, voir Portée Python.
Transmettre des arguments à une autre fonction
L'une des utilisations les plus pratiques de *args/**kwargs est l'écriture de wrappers et de décorateurs qui transmettent les arguments à une fonction interne sans connaître leur nature :
def add_all(*args):
return sum(args)
def wrapper(*args, **kwargs):
print('Calling with args:', args, 'kwargs:', kwargs)
return add_all(*args)
print(wrapper(1, 2, 3))
# Calling with args: (1, 2, 3) kwargs: {}
# 6Ce modèle apparaît partout dans la bibliothèque standard de Python et constitue le fondement des décorateurs et des fonctions d'ordre supérieur.
Ordre complet de la signature
Python impose une règle d'ordre stricte pour tous les types de paramètres. L'ordre complet est :
| Position | Type | Exemple |
|---|---|---|
| 1 | Positionnel uniquement (Python 3.8+) | a, b, / |
| 2 | Positionnel ou nommé normal | x, y |
| 3 | Positionnel variable | *args |
| 4 | Uniquement nommé | flag=True |
| 5 | Nommé variable | **kwargs |
Ne pas respecter cet ordre produit une SyntaxError. Une fonction utilisant les cinq types ressemble à :
def full_sig(pos1, pos2, /, normal, *args, kw_only, **kwargs):
print(pos1, pos2, normal, args, kw_only, kwargs)
full_sig(1, 2, 3, 4, 5, kw_only='k', extra='e')
# 1 2 3 (4, 5) k {'extra': 'e'}Dans le code courant, il est rare d'avoir besoin des cinq à la fois. Les modèles les plus courants sont *args seul, **kwargs seul, ou *args suivi de **kwargs.
Annotations de type
Vous pouvez annoter *args et **kwargs avec des indications de type. L'annotation s'applique à chaque élément individuel, pas au tuple ou au dictionnaire lui-même :
from typing import Any
def add_all(*args: float) -> float:
return sum(args)
def describe(**kwargs: Any) -> None:
for key, value in kwargs.items():
print(f'{key}: {value}')
print(add_all(1.5, 2.5, 3.0)) # 7.0
describe(name='Bob', score=99)
# name: Bob
# score: 99*args: float signifie que chaque élément de args est censé être un float. **kwargs: Any signifie que les valeurs peuvent être de n'importe quel type. Cela satisfait les outils d'analyse statique tout en préservant la flexibilité à l'exécution.
Erreurs courantes
1. Mauvais ordre des arguments dans la signature
Placer **kwargs avant *args est une SyntaxError :
# Wrong — raises SyntaxError
# def bad(name, **kwargs, *args): ...
# Correct
def good(name, *args, **kwargs):
pass2. Modifier le tuple args
args est un tuple et donc immuable. Si vous avez besoin de modifier les arguments, convertissez-les d'abord en liste :
def double_all(*args):
items = list(args) # mutable copy
items = [x * 2 for x in items]
return items
print(double_all(1, 2, 3)) # [2, 4, 6]3. Masquer un nom de paramètre obligatoire
Si vous utilisez *args et avez également un argument nommé avec le même nom qu'un paramètre positionnel, les appelants peuvent être confus. Gardez des noms de paramètres distincts et utilisez des paramètres uniquement nommés (après *args) pour les indicateurs optionnels.
4. Abuser de **kwargs à la place de paramètres explicites
**kwargs masque ce qu'une fonction accepte réellement, rendant l'autocomplétion et l'analyse statique plus difficiles. Préférez des paramètres explicites pour les options que votre fonction prend réellement en charge ; utilisez **kwargs uniquement lorsque l'ensemble des options est véritablement ouvert ou lorsque vous transmettez à une autre fonction.
Récapitulatif
| Fonctionnalité | Syntaxe | Ce qu'elle regroupe | Type à l'intérieur de la fonction |
|---|---|---|---|
| Arguments positionnels variables | *args | Arguments positionnels supplémentaires | tuple |
| Arguments nommés variables | **kwargs | Arguments nommés supplémentaires | dict |
| Décomposer une séquence à l'appel | func(*seq) | Liste/tuple → arguments positionnels | — |
| Décomposer un mapping à l'appel | func(**mapping) | Dict → arguments nommés | — |
Pour des sujets connexes, voir Fonctions Python pour les bases des fonctions, Lambda Python pour les fonctions anonymes, et Portée Python pour la résolution des noms de variables.