Apprenez en lisant dans l'ordre

Arguments à longueur variable *args / **kwargs et valeurs de retour multiples

Apprends args / *kwargs en Python pour accepter un nombre variable d'arguments et renvoyer plusieurs valeurs en un seul appel.

Dans l'article précédent sur def, tu as défini des fonctions avec un nombre fixe d'arguments. Dans le code réel, le nombre d'arguments n'est pas toujours connu d'avance, et parfois tu veux renvoyer plusieurs résultats en un seul appel.

Python gère cela avec les arguments à longueur variable et les valeurs de retour multiples. Les deux s'appuient directement sur ce que tu sais déjà des tuples et des dicts.

Arguments positionnels à longueur variable *args — collecter dans un tuple

Mets une seule astérisque devant le nom d'un argument (*args) et la fonction peut accepter n'importe quel nombre d'arguments positionnels. À l'intérieur de la fonction, ces arguments sont disponibles sous forme de tuple.

Le nom args est la convention, mais techniquement n'importe quel nom descriptif fonctionne — *prices, *messages, ce qui se lit bien pour le cas d'usage.

Collecter des arguments positionnels avec *args
côté appelantsum_all(100, 200, 300)définitiondef sum_all(*prices):dans la fonctionprices = (100, 200, 300)passerregrouper
# Accepte n'importe quel nombre d'arguments positionnels
def sum_all(*prices):
    print(prices)        # (100, 200, 300)
    print(type(prices))  # <class 'tuple'>
    return sum(prices)

print(sum_all(100, 200, 300))   # 600
print(sum_all(500))             # 500 (un seul, ça marche)
print(sum_all())                # 0   (zéro donne un tuple vide)

Combiner des arguments classiques avec *args

Place les arguments classiques avant *args et tu peux combiner un argument fixe en tête avec une queue à longueur variable. Écrire log(level, *messages) veut dire que la première valeur est liée à level et que tout le reste est regroupé dans un tuple appelé messages. L'ordre est arguments classiques → *args.

Arguments classiques combinés avec *args
log("INFO", "Démarré", "Connecté")def log(level, *messages):level = "INFO"messages =("Démarré", "Connecté")passerle premier va à l'arg classiquele reste devient un tuple
def log(level, *messages):
    for m in messages:
        print(f"[{level}] {m}")

log("INFO", "Démarré", "Connecté")
# [INFO] Démarré
# [INFO] Connecté

Écris une fonction qui accepte n'importe quel nombre de prix produit et renvoie leur total.

① Définis def calc_total(*prices): et return sum(prices).

② Affiche le résultat de calc_total(300, 500) et calc_total(120, 280, 550, 400). Confirme que la même fonction marche peu importe combien d'arguments tu passes.

(Une fois le code exécuté correctement, l'explication apparaît.)

Éditeur Python

Exécuter le code pour voir le résultat

Arguments nommés à longueur variable **kwargs — collecter dans un dict

Deux astérisques (`kwargs) permettent à la fonction d'accepter n'importe quels arguments nommés sous la forme name=value. À l'intérieur de la fonction, ces arguments arrivent sous forme de dict, ce qui rend cela parfait quand les clés ne sont pas connues à l'avance**.

Le nom conventionnel est kwargs (raccourci de keyword arguments).

Collecter des arguments nommés avec **kwargs
côté appelantshow(name="Alice", age=30)définitiondef show(**info):dans la fonctioninfo = {"name": "Alice", "age": 30}type: dictpasserregrouper

Appeler show(name="Alice", age=30) donne au receveur le dict {"name": "Alice", "age": 30}. Ne pas avoir à déclarer les clés à l'avance, c'est tout l'intérêt.

def describe_user(**info):
    print(info)            # {'name': 'Alice', 'age': 30, 'city': 'Paris'}
    print(type(info))      # <class 'dict'>
    for key, value in info.items():
        print(f"{key}: {value}")

describe_user(name="Alice", age=30, city="Paris")

Combiner des arguments classiques avec **kwargs

Place un argument classique avant **kwargs et tu obtiens **une valeur fixe obligatoire** plus **des champs optionnels flexibles**. Définir def save_user(name, **info): veut dire que name est toujours requis, tandis que des champs supplémentaires comme age=30 ou city="Paris" se font collecter dans le dict info.

Arguments classiques combinés avec **kwargs
save_user("Alice", age=30, city="Paris")def save_user(name, **info):name = "Alice"info ={"age": 30, "city": "Paris"}passerle premier va à l'arg classiquele reste devient un dict
def save_user(name, **info):
    print(f"name: {name}")
    for key, value in info.items():
        print(f"{key}: {value}")

save_user("Alice", age=30, city="Paris")
# name: Alice
# age: 30
# city: Paris

Écris une fonction qui prend les infos utilisateur en arguments nommés et affiche chaque entrée sur sa propre ligne.

① Définis def show_profile(**info): et boucle avec for key, value in info.items(): en affichant f"{key}: {value}".

② Appelle-la avec show_profile(name="Alice", age=20, city="Lyon").

Éditeur Python

Exécuter le code pour voir le résultat

Utiliser arguments classiques, *args et **kwargs ensemble

Les trois sortes d'arguments peuvent coexister dans une seule fonction. L'ordre est figé : arguments classiques → *args → **kwargs. Écrire def register(user_id, *tags, **meta): lie la première valeur à user_id, regroupe tout argument positionnel supplémentaire dans le tuple tags, et regroupe chaque argument key=value dans le dict meta.

def register(user_id, *tags, **meta):
    print(f"id: {user_id}")
    print(f"tags: {tags}")
    print(f"meta: {meta}")

register(1001, "admin", "beta", email="alice@example.com", active=True)
# id: 1001
# tags: ('admin', 'beta')
# meta: {'email': 'alice@example.com', 'active': True}

Écris une fonction qui utilise des arguments classiques, *args et **kwargs en même temps.

① Définis def register(user_id, *tags, **meta): et affiche trois lignes : f"id: {user_id}", f"tags: {tags}" et f"meta: {meta}".

② Appelle register(1001, "admin", "beta", email="alice@example.com", active=True) et observe comment chaque argument se range à sa place.

Éditeur Python

Exécuter le code pour voir le résultat

Dépaquetage côté appelant — *list / **dict

Quand tu passes une liste ou un dict existants à une fonction, mettre ou non * ou ** devant change le résultat de manière radicale.

Si tu la passes telle quelle sans * ni **, la liste ou le dict est traité **comme une seule valeur qui ne se dépaquette pas**. Reçois-la via *args et tu finiras avec un tuple contenant une liste (par ex. ([1, 2, 3],)`) — c'est le piège.

Avec `list / dict côté appel, le contenu est étalé un par un, donc *args / **kwargs voient bien le tuple (1, 2, 3) ou le dict {"name": "Alice"} attendus.

Mettre * ou non change ce que *args contient
lst = [1, 2, 3]f(lst)(sans *)args =([1, 2, 3],)(une liste)lst = [1, 2, 3]f(*lst)(avec *)args =(1, 2, 3)(dépaqueté)reste en un seulétalé
def sum_all(*prices):
    return sum(prices)

prices = [120, 280, 550]

# X : passé comme une seule liste
# print(sum_all(prices))     # erreur (sum essaie d'additionner la liste elle-même à des nombres)

# O : étale-la avec `*`
print(sum_all(*prices))       # 950 — pareil que sum_all(120, 280, 550)

# Même idée avec les dicts
def announce(name, city):
    print(f"{name} de {city}")

user = {"name": "Léa", "city": "Marseille"}
announce(**user)              # pareil que announce(name="Léa", city="Marseille")

Le dépaquetage brille quand on passe des données existantes

Quand tu as déjà des données sous forme de liste ou de dict, le dépaquetage les fait entrer dans une fonction en une seule ligne.

Par exemple, le dict user = {"name": "Léa", "city": "Marseille"} devient announce(**user) — c'est pareil qu'écrire announce(name="Léa", city="Marseille"). Pas besoin d'extraire chaque clé à la main.

Prends la liste existante cart_prices = [480, 1200, 320, 980] et étale-la dans la fonction calc_total vue plus haut.

① Redéfinis def calc_total(*prices): qui renvoie sum(prices).

② Déclare cart_prices = [480, 1200, 320, 980] et print() le résultat de calc_total(*cart_prices).

③ Essaie print(calc_total(cart_prices)) sans l'astérisque. Tu obtiendras une erreur — lis-la et confirme que la liste elle-même finit comme premier argument.

Éditeur Python

Exécuter le code pour voir le résultat

Valeurs de retour multiples — renvoyer un tuple, dépaqueter à la réception

return accepte plusieurs valeurs séparées par des virgules, et l'appelant reçoit un tuple de ces valeurs. Reçois-les avec a, b = function() pour dépaqueter le tuple en plusieurs variables d'un coup.

C'est pratique chaque fois que tu veux renvoyer plusieurs valeurs depuis une fonction (min et max, nom d'utilisateur et rôle, drapeau de succès et message, etc.).

Les valeurs de retour multiples reviennent sous forme de tuple
def get_person():return name, age, city(name, age, city)(tuple)result = get_person()# result reste un tuplename, age, city= get_person()se répartit enname, age, cityvaleur réelledépaqueter
# Renvoyer plusieurs valeurs en une fois
def get_person():
    return "Alice", 30, "Paris"

# Recevoir comme un tuple
result = get_person()
print(result)            # ('Alice', 30, 'Paris')
print(type(result))      # <class 'tuple'>

# Ou dépaqueter en variables individuelles
name, age, city = get_person()
print(name, age, city)   # Alice 30 Paris

# Exemple concret : renvoyer min et max ensemble
def get_min_max(values):
    return min(values), max(values)

lowest, highest = get_min_max([120, 500, 300, 180])
print(f"min {lowest} / max {highest}")

Utilise *rest pour récupérer ce qui reste

Avec une liste de notes comme return 90, 85, 78, 92, 88, écris first, *middle, last = ... et tu obtiendras first=90, last=88, middle=[85, 78, 92]les premières et dernières valeurs, et le reste rassemblé dans une liste. C'est l'outil parfait quand tu veux garder seulement le début et la fin et regrouper tout ce qui est entre les deux.

Écris une fonction qui renvoie à la fois le prix le plus bas et le plus haut d'une liste de produits.

① Définis def get_price_range(prices): et return min(prices), max(prices) pour renvoyer deux valeurs.

② Prépare product_prices = [480, 1200, 320, 980, 650] et dépaquette le résultat avec lowest, highest = get_price_range(product_prices).

③ Affiche f"Lowest: {lowest}" et f"Highest: {highest}".

Éditeur Python

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Que va afficher ce code ?
def f(*args):
return sum(args)

print(f(1, 2, 3, 4))

Question 2Quel est le type de kwargs reçu par def f(**kwargs): ?

Question 3Avec nums = [1, 2, 3], quel appel passe son contenu comme trois arguments positionnels à f(a, b, c) ?