W3docs

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 :

  1. Paramètres positionnels normaux
  2. *args
  3. Paramètres uniquement nommés (avec valeurs par défaut)
  4. **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: True

port 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: {}
# 6

Ce 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 :

PositionTypeExemple
1Positionnel uniquement (Python 3.8+)a, b, /
2Positionnel ou nommé normalx, y
3Positionnel variable*args
4Uniquement nomméflag=True
5Nommé 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):
    pass

2. 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éSyntaxeCe qu'elle regroupeType à l'intérieur de la fonction
Arguments positionnels variables*argsArguments positionnels supplémentairestuple
Arguments nommés variables**kwargsArguments nommés supplémentairesdict
Décomposer une séquence à l'appelfunc(*seq)Liste/tuple → arguments positionnels
Décomposer un mapping à l'appelfunc(**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.

Pratique

Pratique
In Python, what does *args do when used in a function definition?
In Python, what does *args do when used in a function definition?
Was this page helpful?