Appeler append() sur une liste Python ne renvoie rien. La méthode retourne None, et c’est précisément ce détail qui piège les débutants : l’opération ne produit pas une nouvelle liste, elle modifie celle qui existe déjà en mémoire. Derrière ce comportement se cache un mécanisme fondamental, la mutation d’objet en Python, qui conditionne la façon dont les listes interagissent avec les variables, les fonctions et les copies.
Pourquoi append renvoie None : la logique de mutation en place
La plupart des langages proposent deux familles d’opérations sur les collections : celles qui créent un nouvel objet et celles qui modifient l’objet existant. En Python, append() appartient à la seconde catégorie. La méthode agit directement sur la liste en mémoire, sans produire de copie.
Le retour None est un choix de conception délibéré. Guido van Rossum a opté pour cette convention afin de rendre explicite la différence entre mutation et création. Quand une méthode modifie un objet mutable, elle ne retourne pas l’objet modifié. Le piège classique ressemble à ceci :
ma_liste = [1, 2, 3].append(4)
Après cette ligne, ma_liste vaut None, pas [1, 2, 3, 4]. La liste temporaire [1, 2, 3] a bien reçu l’élément 4, mais aucune variable ne la référence plus. Elle est perdue.
La bonne approche sépare toujours la création et la mutation :
ma_liste = [1, 2, 3]ma_liste.append(4)
Deux lignes, pas une. La liste est d’abord liée à un nom, puis modifiée via ce nom.
Alias et références : le vrai piège de append sur une liste Python
La mutation ne pose pas uniquement un problème de valeur de retour. Elle devient réellement dangereuse quand plusieurs noms pointent vers le même objet en mémoire.

Prenons un cas concret. Si vous écrivez a = [1, 2, 3] puis b = a, les deux variables référencent exactement la même liste. L’opérateur is le confirme : a is b retourne True. Il ne s’agit pas d’une copie, mais d’un alias.
Toute mutation via a.append(4) se reflète immédiatement dans b, puisque a et b désignent le même objet. Append ne copie pas la liste, il modifie l’objet partagé.
Ce comportement surprend quand on vient de langages où l’affectation crée systématiquement une copie. En Python, l’affectation lie un nom à une référence, jamais à une valeur. La distinction entre identité (is) et égalité (==) prend ici tout son sens.
Pour obtenir une liste indépendante, il faut créer une copie explicite :
b = a[:]oub = list(a)produisent une copie superficielle (shallow copy) : les éléments de premier niveau sont dupliqués, mais les objets imbriqués restent partagésb = copy.deepcopy(a)crée une copie récursive complète, y compris les sous-listes et les objets contenusb = a.copy()est équivalent à la copie superficielle, disponible depuis Python 3.3
Append et les objets imbriqués : une référence, pas une copie
Un deuxième piège découle du premier. Quand vous passez un objet à append(), la méthode n’en fait pas de copie. Elle ajoute une référence directe vers l’objet passé en argument.
Considérez ce code :
sous_liste = [10, 20]principale = []principale.append(sous_liste)
La liste principale contient maintenant [[10, 20]]. Modifier sous_liste après l’ajout (par exemple sous_liste.append(30)) modifie aussi le contenu visible dans principale, qui affiche désormais [[10, 20, 30]].
Ce mécanisme de référence explique pourquoi append produit une sous-liste et non un aplatissement. Si vous voulez fusionner les éléments d’une liste dans une autre, c’est extend() qu’il faut utiliser, pas append().

Liste Python et tableau dynamique : ce que append fait en mémoire
Sous le capot, une liste Python fonctionne comme un tableau dynamique de références. Chaque élément de la liste est un pointeur vers un objet situé ailleurs en mémoire, pas l’objet lui-même.
Quand append() ajoute un élément, l’opération est généralement très rapide. La liste maintient un espace mémoire pré-alloué au-delà de sa taille courante. Tant que cet espace suffit, l’ajout se résume à écrire une nouvelle référence et à incrémenter un compteur interne.
Lorsque l’espace pré-alloué est épuisé, Python déclenche une réallocation : il crée un nouveau bloc mémoire plus grand, copie les références existantes, puis libère l’ancien bloc. Cette réallocation est ponctuelle. L’append reste rapide en moyenne grâce à une stratégie de sur-allocation qui espace ces opérations coûteuses.
Cette architecture explique aussi pourquoi insérer un élément en début de liste (insert(0, x)) coûte plus cher : tous les pointeurs doivent être décalés. Pour des insertions fréquentes en tête, le type collections.deque est plus adapté.
Append dans une fonction : effets de bord et paramètres par défaut
Quand une liste est passée en argument à une fonction, Python transmet la référence, pas une copie. Appeler append() à l’intérieur de la fonction modifie la liste de l’appelant.
Ce comportement est un effet de bord. Il peut être utile (construire une liste de résultats progressivement) ou destructeur (modifier accidentellement des données en dehors du périmètre de la fonction).
Le piège le plus documenté concerne les paramètres par défaut mutables :
def ajouter(element, cible=[]): cible.append(element) return cible
À chaque appel sans second argument, Python réutilise la même liste par défaut. Les éléments s’accumulent d’un appel à l’autre, un comportement que la majorité des développeurs ne souhaitent pas. La convention consiste à utiliser None comme valeur par défaut et à créer la liste dans le corps de la fonction :
def ajouter(element, cible=None):puisif cible is None: cible = []garantit une liste neuve à chaque appel- Ce pattern est recommandé dans la documentation officielle Python et dans la plupart des linters (Pylint, Ruff)
- Le même risque s’applique à tout objet mutable utilisé comme valeur par défaut : dictionnaires, sets, instances de classes personnalisées
La mutation d’objet via append() n’a rien de mystérieux une fois qu’on a intégré trois principes : la méthode modifie la liste existante au lieu d’en créer une nouvelle, l’affectation en Python lie un nom à une référence et non à une copie, et tout argument passé à append est stocké par référence. Garder ces trois règles en tête suffit à éviter la quasi-totalité des bugs liés aux listes mutables.

