Qu'est-ce que **kwargs en Python ? Guide complet

Découvrez **kwargs en Python : définition, exemples pratiques et bonnes pratiques pour utiliser les arguments nommés variables dans vos fonctions.
10 min de lecture
Believemy logo

Définition de **kwargs en Python

En Python, **kwargs est un paramètre spécial utilisé dans la définition d'une fonction pour accepter un nombre variable d'arguments nommés (keyword arguments). Le terme "kwargs" est une abréviation de "keyword arguments". Concrètement, lorsque vous écrivez **kwargs dans la signature d'une fonction, Python collecte tous les arguments nommés supplémentaires passés à cette fonction et les stocke dans un dict (dictionnaire).

Ce mécanisme est extrêmement puissant : il vous permet de créer des fonctions flexibles capables de recevoir un nombre indéterminé de paramètres sans avoir à les déclarer explicitement. C'est un concept fondamental que vous retrouverez dans de nombreuses bibliothèques Python et que nous explorons en profondeur dans notre formation complète sur Python.

Bon à savoir

Le double astérisque ** est l'opérateur clé. Le nom "kwargs" est une simple convention : vous pourriez tout aussi bien écrire **options ou **parametres. C'est le ** qui indique à Python de capturer les arguments nommés.


Comment fonctionne **kwargs ?

Lorsqu'une fonction est appelée avec des arguments nommés qui ne correspondent pas aux paramètres définis explicitement, Python les regroupe dans un dictionnaire. Les noms des arguments deviennent les clés du dictionnaire, et les valeurs passées deviennent les valeurs associées.

Voici un premier exemple simple :

PYTHON
def afficher_infos(**kwargs):
    for cle, valeur in kwargs.items():
        print(f"{cle} : {valeur}")

afficher_infos(nom="Alice", age=30, ville="Paris")

Ce code affiche :

PYTHON
nom : Alice
age : 30
ville : Paris

Comme vous pouvez le constater, les trois arguments nommés nom, age et ville ont été automatiquement collectés dans le dictionnaire kwargs. Vous pouvez ensuite parcourir ce dictionnaire avec la méthode .items() pour accéder aux paires clé-valeur.


Différence entre *args et **kwargs

Il est essentiel de bien distinguer *args et **kwargs. Ces deux mécanismes sont complémentaires mais fonctionnent différemment :

Caractéristique*args**kwargs
Type de conteneurtupledict
Arguments acceptésPositionnels (sans nom)Nommés (avec nom)
Syntaxe d'appelfunc(1, 2, 3)func(a=1, b=2)
Accès aux valeursPar indexPar clé

Voici un exemple qui combine les deux :

PYTHON
def fonction_complete(*args, **kwargs):
    print("Arguments positionnels :", args)
    print("Arguments nommés :", kwargs)

fonction_complete(1, 2, 3, nom="Alice", age=30)

Résultat :

PYTHON
Arguments positionnels : (1, 2, 3)
Arguments nommés : {'nom': 'Alice', 'age': 30}
Attention

L'ordre des paramètres dans la signature d'une fonction est important : les paramètres classiques viennent en premier, puis *args, puis **kwargs. Inverser cet ordre provoquera une erreur de syntaxe.


Exemples pratiques d'utilisation de **kwargs

Créer une fonction de configuration flexible

L'un des cas d'utilisation les plus courants de **kwargs est la création de fonctions de configuration. Vous pouvez définir des valeurs par défaut tout en permettant à l'utilisateur de les surcharger :

PYTHON
def configurer_application(**kwargs):
    config = {
        "debug": False,
        "port": 8080,
        "host": "localhost",
        "timeout": 30
    }
    config.update(kwargs)
    return config

# Utilisation avec des paramètres personnalisés
ma_config = configurer_application(debug=True, port=3000)
print(ma_config)
# {'debug': True, 'port': 3000, 'host': 'localhost', 'timeout': 30}

Dans cet exemple, la fonction définit un dictionnaire de configuration par défaut, puis utilise update() pour remplacer les valeurs spécifiées par l'utilisateur. C'est un patron de conception très répandu dans l'écosystème Python.


Transmettre des arguments à une autre fonction

Une autre utilisation très fréquente de **kwargs est la transmission d'arguments à une fonction sous-jacente. C'est un patron que vous retrouverez souvent dans les décorateurs et les fonctions enveloppes :

PYTHON
def journaliser_appel(func):
    def wrapper(*args, **kwargs):
        print(f"Appel de {func.__name__} avec kwargs: {kwargs}")
        resultat = func(*args, **kwargs)
        print(f"Résultat : {resultat}")
        return resultat
    return wrapper

@journaliser_appel
def calculer_prix(prix_base, taxe=0.2, remise=0):
    return prix_base * (1 + taxe) - remise

calculer_prix(100, taxe=0.1, remise=5)

Résultat :

PYTHON
Appel de calculer_prix avec kwargs: {'taxe': 0.1, 'remise': 5}
Résultat : 105.0

Ici, le décorateur journaliser_appel utilise **kwargs dans sa fonction wrapper pour intercepter et transmettre tous les arguments nommés sans avoir besoin de les connaître à l'avance.


Construire des classes avec des options variables

Vous pouvez utiliser **kwargs dans la méthode __init__ d'une class pour permettre une initialisation flexible :

PYTHON
class Widget:
    def __init__(self, nom, **kwargs):
        self.nom = nom
        self.largeur = kwargs.get("largeur", 100)
        self.hauteur = kwargs.get("hauteur", 50)
        self.couleur = kwargs.get("couleur", "blanc")
        self.visible = kwargs.get("visible", True)
    
    def __repr__(self):
        return (f"Widget(nom='{self.nom}', largeur={self.largeur}, "
                f"hauteur={self.hauteur}, couleur='{self.couleur}')")

# Création avec différentes options
bouton = Widget("MonBouton", couleur="bleu", largeur=200)
print(bouton)
# Widget(nom='MonBouton', largeur=200, hauteur=50, couleur='bleu')

La méthode .get() du dictionnaire est particulièrement utile ici, car elle vous permet de définir une valeur par défaut si la clé n'existe pas dans kwargs.


Dépaquetage de dictionnaire avec **

L'opérateur ** ne sert pas uniquement à capturer des arguments. Il peut aussi dépaqueter un dictionnaire pour le passer comme arguments nommés à une fonction :

PYTHON
def creer_profil(nom, age, ville, profession):
    return f"{nom}, {age} ans, {ville} - {profession}"

infos = {
    "nom": "Alice",
    "age": 30,
    "ville": "Paris",
    "profession": "Développeuse"
}

# Dépaquetage du dictionnaire
profil = creer_profil(**infos)
print(profil)
# Alice, 30 ans, Paris - Développeuse

Cette technique est extrêmement pratique quand vous avez vos données déjà structurées dans un dictionnaire. L'opérateur ** "déballe" chaque paire clé-valeur du dictionnaire en argument nommé correspondant.


Fusionner des dictionnaires avec **

Depuis Python 3.5, vous pouvez utiliser ** pour fusionner plusieurs dictionnaires de manière élégante :

PYTHON
defauts = {"theme": "clair", "langue": "fr", "notifications": True}
preferences_utilisateur = {"theme": "sombre", "taille_police": 14}

# Fusion avec ** (Python 3.5+)
config_finale = {**defauts, **preferences_utilisateur}
print(config_finale)
# {'theme': 'sombre', 'langue': 'fr', 'notifications': True, 'taille_police': 14}

# Alternative avec | (Python 3.9+)
config_finale_v2 = defauts | preferences_utilisateur
print(config_finale_v2)
# {'theme': 'sombre', 'langue': 'fr', 'notifications': True, 'taille_police': 14}

Notez que lorsque des clés sont identiques, c'est le dernier dictionnaire qui l'emporte. Ici, "theme" vaut "sombre" car preferences_utilisateur est dépacqueté en second.


Combiner paramètres classiques, *args et **kwargs

Lorsque vous combinez différents types de paramètres, vous devez respecter un ordre strict dans la signature de votre fonction def :

PYTHON
def fonction_universelle(param_obligatoire, param_defaut="valeur", *args, **kwargs):
    print(f"Obligatoire : {param_obligatoire}")
    print(f"Avec défaut : {param_defaut}")
    print(f"Args supplémentaires : {args}")
    print(f"Kwargs supplémentaires : {kwargs}")

fonction_universelle("hello", "world", 1, 2, 3, debug=True, verbose=False)

Résultat :

PYTHON
Obligatoire : hello
Avec défaut : world
Args supplémentaires : (1, 2, 3)
Kwargs supplémentaires : {'debug': True, 'verbose': False}

L'ordre à respecter est toujours le suivant :

  1. Paramètres positionnels obligatoires
  2. Paramètres avec valeur par défaut
  3. *args — arguments positionnels variables
  4. **kwargs — arguments nommés variables
Attention

**kwargs doit toujours être le dernier paramètre de la signature. Placer quoi que ce soit après **kwargs provoquera une SyntaxError.


Bonnes pratiques avec **kwargs

1. Validez les clés reçues

Un inconvénient de **kwargs est qu'il accepte n'importe quel argument nommé, y compris ceux contenant des fautes de frappe. Pensez à valider les clés :

PYTHON
def configurer(**kwargs):
    cles_valides = {"debug", "port", "host", "timeout"}
    cles_inconnues = set(kwargs.keys()) - cles_valides
    
    if cles_inconnues:
        raise TypeError(f"Arguments inconnus : {cles_inconnues}")
    
    return kwargs

# Ceci lèvera une erreur
try:
    configurer(debuq=True)  # Faute de frappe !
except TypeError as e:
    print(e)  # Arguments inconnus : {'debuq'}


2. Préférez les paramètres explicites quand c'est possible

N'utilisez pas **kwargs comme raccourci pour éviter de déclarer des paramètres. Si vous connaissez les paramètres attendus, déclarez-les explicitement pour une meilleure lisibilité et un meilleur support de l'autocomplétion :

PYTHON
# ❌ Moins lisible
def creer_utilisateur(**kwargs):
    nom = kwargs.get("nom")
    email = kwargs.get("email")
    age = kwargs.get("age", 0)

# ✅ Plus explicite et lisible
def creer_utilisateur(nom, email, age=0):
    pass


3. Documentez les kwargs attendus

Lorsque vous utilisez **kwargs, ajoutez une docstring détaillée pour indiquer les arguments nommés acceptés :

PYTHON
def envoyer_email(destinataire, sujet, **kwargs):
    """Envoie un email.
    
    Args:
        destinataire: Adresse email du destinataire.
        sujet: Sujet de l'email.
        **kwargs: Options supplémentaires :
            - cc (str): Adresse en copie.
            - bcc (str): Adresse en copie cachée.
            - priorite (int): Niveau de priorité (1-5).
            - html (bool): Envoyer en HTML (défaut: False).
    """
    cc = kwargs.get("cc")
    bcc = kwargs.get("bcc")
    priorite = kwargs.get("priorite", 3)
    html = kwargs.get("html", False)
    # ... logique d'envoi


4. Utilisez kwargs pour l'héritage et la délégation

Dans les hiérarchies de classes, **kwargs est idéal pour transmettre des arguments au constructeur parent sans les lister tous :

PYTHON
class Animal:
    def __init__(self, nom, age, **kwargs):
        self.nom = nom
        self.age = age
        self.attributs = kwargs

class Chien(Animal):
    def __init__(self, race, **kwargs):
        super().__init__(**kwargs)
        self.race = race

mon_chien = Chien(race="Labrador", nom="Rex", age=5, couleur="doré")
print(mon_chien.nom)        # Rex
print(mon_chien.race)       # Labrador
print(mon_chien.attributs)  # {'couleur': 'doré'}


Cas d'utilisation avancés

Kwargs avec des annotations de type

Depuis Python 3.12, vous pouvez utiliser TypedDict et Unpack pour typer précisément vos **kwargs :

PYTHON
from typing import TypedDict, Unpack

class ConfigOptions(TypedDict, total=False):
    debug: bool
    port: int
    host: str

def demarrer_serveur(**kwargs: Unpack[ConfigOptions]) -> None:
    debug = kwargs.get("debug", False)
    port = kwargs.get("port", 8080)
    host = kwargs.get("host", "localhost")
    print(f"Serveur sur {host}:{port} (debug={debug})")

demarrer_serveur(debug=True, port=3000)

Cette approche offre le meilleur des deux mondes : la flexibilité de **kwargs avec la sécurité du typage statique.


Kwargs dans les fonctions lambda

Les fonctions lambda peuvent également utiliser **kwargs, même si cela reste peu courant :

PYTHON
# Lambda avec **kwargs
afficher = lambda **kwargs: print(", ".join(f"{k}={v}" for k, v in kwargs.items()))
afficher(x=1, y=2, z=3)
# x=1, y=2, z=3


Erreurs courantes à éviter

Voici les erreurs les plus fréquentes lorsque vous travaillez avec **kwargs :

PYTHON
# ❌ Erreur 1 : Oublier ** lors du dépaquetage
def saluer(nom, ville):
    print(f"Bonjour {nom} de {ville}")

infos = {"nom": "Alice", "ville": "Paris"}
# saluer(infos)       # TypeError !
saluer(**infos)        # ✅ Correct

# ❌ Erreur 2 : Clés du dictionnaire non-string
# **kwargs n'accepte que des clés de type string
mauvais_dict = {1: "un", 2: "deux"}
# def test(**kwargs): pass
# test(**mauvais_dict)  # TypeError !

# ❌ Erreur 3 : Argument en double
def dire_bonjour(nom, **kwargs):
    pass
# dire_bonjour("Alice", nom="Bob")  # TypeError: multiple values for argument 'nom'
Attention

Les clés d'un dictionnaire dépacqueté avec ** doivent obligatoirement être des chaînes de caractères. Toute autre type de clé provoquera une TypeError.


Questions fréquentes

Question

Quelle est la différence entre *args et **kwargs ?

*args collecte les arguments positionnels supplémentaires dans un tuple, tandis que **kwargs collecte les arguments nommés supplémentaires dans un dict. Par exemple, dans func(1, 2, nom="Alice"), les valeurs 1 et 2 iraient dans args, et nom="Alice" irait dans kwargs. Les deux peuvent être utilisés dans la même fonction, mais *args doit toujours précéder **kwargs.


Question

Le nom "kwargs" est-il obligatoire ?

Non, kwargs est simplement une convention communément adoptée par la communauté Python. Vous pouvez utiliser n'importe quel nom de variable valide après le double astérisque **. Par exemple, **options, **parametres ou **config fonctionneront parfaitement. Cependant, nous vous recommandons fortement de respecter la convention **kwargs pour que votre code soit immédiatement compréhensible par d'autres développeurs.


Question

Peut-on modifier kwargs à l'intérieur d'une fonction ?

Oui, kwargs est un dictionnaire Python classique. Vous pouvez librement ajouter, modifier ou supprimer des clés. Cependant, ces modifications ne seront visibles que dans le scope de la fonction, elles n'affecteront pas les variables de l'appelant. C'est un comportement identique à celui de n'importe quel dict passé comme argument.


Question

Comment apprendre à maîtriser **kwargs et les fonctions Python ?

Pour bien maîtriser **kwargs, il est essentiel de pratiquer avec des exemples concrets : décorateurs, classes avec héritage, fonctions de configuration. Nous vous recommandons de suivre notre formation dédiée à Python sur Believemy, qui couvre en détail les fonctions, les arguments variables, les décorateurs et bien d'autres concepts avancés avec des exercices pratiques.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.