Comment Déballer des Itérables avec l’Astérisque * en Python ?

Introduction

L’opérateur astérisque (*) de Python est plus puissant qu’il n’y paraît. Bien que les débutants le rencontrent souvent d’abord dans le contexte de la multiplication, il joue un rôle beaucoup plus vaste et élégant lorsqu’il s’agit de déballer des itérables, de collecter des arguments de fonctions, et de manipuler des structures de données dynamiques.

Dans cet article, nous allons explorer comment * et son homologue à double astérisque ** sont utilisés pour déballer et reconditionner les données en Python.

Que signifie « déballer » ?

Déballer, c’est extraire les valeurs d’un itérable (comme une liste, un tuple, un ensemble ou une chaîne) et les affecter à des variables individuelles. C’est la manière qu’a Python de dire : « Décompose cette collection et distribue les éléments. »

Deux types principaux de déballage :

  • Déballage à gauche : Distribution des éléments dans des variables (a, *reste = iterable)
  • Déballage dans les arguments de fonctions : Passage des éléments en arguments avec * ou **

Déballage de base de listes/tuples avec *

Python permet de déballer les valeurs directement dans des variables. L’opérateur * rend cela plus flexible en collectant le reste des éléments dans une liste :

1
2
3
4
a, b, *reste = [1, 2, 3, 4, 5]
print(a)      # 1
print(b)      # 2
print(reste)  # [3, 4, 5]

On peut placer * à différentes positions :

1
2
3
4
5
6
*debut, fin = [10, 20, 30, 40]
print(debut)  # [10, 20, 30]
print(fin)    # 40

premier, *milieu, dernier = [1, 2, 3, 4, 5]
print(milieu)  # [2, 3, 4]

⚠️ On ne peut utiliser qu’une seule cible étoilée (*) par affectation.

Déballage de base de dictionnaires avec **

Le double astérisque ** permet de déballer des dictionnaires — une fonctionnalité puissante pour fusionner des dictionnaires ou passer leurs contenus à des fonctions sous forme d’arguments nommés.

Exemple de base

1
2
3
4
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3}
fusion = {**dict1, **dict2}
print(fusion)  # {'a': 1, 'b': 2, 'c': 3}

Ce qu’il se passe ici :

  • **dict1 déballe les paires clé-valeur de dict1.
  • **dict2 déballe dict2 de la même façon.
  • Le résultat est un nouveau dictionnaire combiné.

Fonctionnalité introduite avec Python 3.5+.

Écrasement des clés

Si les deux dictionnaires ont la même clé, le dernier l’emporte :

1
2
3
4
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 99, "c": 3}
fusion = {**dict1, **dict2}
print(fusion)  # {'a': 1, 'b': 99, 'c': 3}

Fusion de plusieurs dictionnaires

1
2
3
4
5
d1 = {"x": 1}
d2 = {"y": 2}
d3 = {"z": 3}
fusion = {**d1, **d2, **d3}
print(fusion)  # {'x': 1, 'y': 2, 'z': 3}

Avec des littéraux

1
2
3
defaults = {"theme": "light", "font": "Arial"}
settings = {**defaults, "font": "Helvetica", "size": 12}
print(settings)  # {'theme': 'light', 'font': 'Helvetica', 'size': 12}

Cas limites

1
2
3
4
5
6
7
bad = [("a", 1), ("b", 2)]
# ❌ TypeError: 'list' object is not a mapping
# fusion = {**bad}

# Solution :
valid = dict(bad)
fusion = {**valid}

Comparaison avec update()

  • {**d1, **d2} crée un nouveau dictionnaire.
  • d1.update(d2) modifie d1 en place.

Code:

1
2
3
4
d1 = {"a": 1}
d2 = {"b": 2}
fusion = {**d1, **d2}
d1.update(d2)  # modifie d1

Utilisez ** si vous souhaitez préserver l’immuabilité.

*args et **kwargs dans les fonctions

Python permet à une fonction d’accepter un nombre variable d’arguments :

  • *args : arguments positionnels (regroupés en tuple)
  • **kwargs : arguments nommés (regroupés en dictionnaire)

Exemple *args

1
2
3
4
5
def saluer(*noms):
    for nom in noms:
        print(f"Bonjour, {nom}!")

saluer("Alice", "Bob", "Charlie")

Sortie:

1
2
3
Bonjour, Alice!
Bonjour, Bob!
Bonjour, Charlie!

Exemple **kwargs

1
2
3
4
5
def afficher_infos(**infos):
    for cle, valeur in infos.items():
        print(f"{cle}: {valeur}")

afficher_infos(nom="Dana", age=30, role="Ingénieure")

Sortie:

1
2
3
name: Dana
age: 30
role: Engineer

Déballage dans les appels de fonction

Vous pouvez déballer un itérable ou un dictionnaire pour passer ses valeurs à une fonction :

1
2
3
4
5
def addition(a, b, c):
    return a + b + c

nombres = [1, 2, 3]
print(addition(*nombres))  # 6

Avec un dictionnaire :

1
2
3
4
5
def introduire(nom, age):
    print(f"{nom} a {age} ans.")

info = {'nom': 'Dana', 'age': 30}
introduire(**info)

Fusion et copie d’itérables avec *

Fusion de listes

1
2
3
4
liste1 = [1, 2]
liste2 = [3, 4]
fusion = [*liste1, *liste2]
print(fusion)  # [1, 2, 3, 4]

Copie superficielle

1
copie = [*liste1]

Fusion de dictionnaires

1
2
3
d1 = {'a': 1}
d2 = {'b': 2}
fusion = {**d1, **d2}

Déballage dans les boucles

1
2
3
4
5
6
7
data = [(1, 2, 3), (4, 5, 6)]
for a, *milieu, c in data:
    print(milieu)

# Affiche :
# [2]
# [5]

Déballage de structures imbriquées

1
2
3
4
5
6
nested = [(1, (2, 3)), (4, (5, 6))]
for x, (y, z) in nested:
    print(x, y, z)

# x=1, y=2, z=3
# x=4, y=5, z=6

Avec longueurs variables :

1
2
3
nested = [(1, (2, 3, 4)), (5, (6, 7))]
for x, (y, *reste) in nested:
    print(f"x={x}, y={y}, reste={reste}")

Pièges courants

  • ❌ Un seul * autorisé par déballage :

    1
    2
    # ❌ Invalid
    # a, *b, *c = [1, 2, 3]
    
  • * et ** ne fonctionnent que sur des itérables.

  • Lors du déballage dans une fonction, le nombre d’éléments doit correspondre à sa signature (sauf avec *args ou **kwargs).

Tableau récapitulatif

Cas d’usage Exemple de syntaxe
Affectation avec reste a, *b = [1, 2, 3]
Fonction à arguments variables def f(*args):
Fonction à mots-clés variables def f(**kwargs):
Déballer une liste dans une fonction f(*[1, 2, 3])
Déballer un dictionnaire dans une fonction f(**{'x': 1, 'y': 2})
Fusionner des listes [ *a, *b ]
Fusionner des dictionnaires { **d1, **d2 }
Boucle avec reste for a, *b, c in data:

Conclusion

Les opérateurs * et ** sont des outils essentiels pour écrire un code Python clair, concis et élégant. Ils facilitent la gestion des arguments, le déballage de données, la fusion de structures, et la manipulation de données complexes ou de longueur variable.

Savoir quand et comment les utiliser rendra votre code non seulement plus court — mais aussi plus lisible, plus propre, et plus "pythonic".