del en Python : supprimer un nom ou un élément

En Python, del efface un nom, un élément de liste, une entrée de dictionnaire ou un attribut : il retire une référence, pas forcément l'objet.
6 min de lecture
Believemy logo

Définition

Un programme accumule des choses dont il n'a plus besoin : une clé de configuration devenue fausse, une variable qui ne doit surtout pas resservir plus bas. Le plus souvent, il suffit de ne plus s'en occuper ; parfois la donnée gêne vraiment, et il faut l'effacer.

del est le mot que Python réserve à ce geste. C'est une instruction, pas une fonction : elle ne prend pas de parenthèses, ne renvoie rien, et ne peut donc jamais se placer à droite d'un signe égal. Ce statut à part a une raison : elle agit sur la cible elle-même, alors qu'une fonction ne reçoit que le contenu d'une variable, jamais l'étiquette qui la désigne.

Selon ce qui le suit, del efface un nom de l'espace courant, un élément d'une liste, une entrée de dictionnaire ou un attribut d'objet. Voici les deux usages les plus fréquents.

PYTHON
stock = {"pommes": 12, "poires": 4}
del stock["poires"]
print(stock)
# {'pommes': 12}

nombres = [10, 20, 30, 40]
del nombres[1]
print(nombres)
# [10, 30, 40]

La collection est modifiée sur place : c'est l'objet d'origine qui a changé, et rien ne revient de l'opération, pas même l'élément retiré.

C'est là que del se sépare de pop et remove, deux méthodes attachées à un type précis. Lui appartient à la grammaire, comme if ou return, et fonctionne à l'identique sur des objets sans rapport.


Supprimer un nom n'est pas supprimer l'objet

Voilà le malentendu qui coûte le plus cher : beaucoup lisent del comme un ordre de destruction, une place rendue en mémoire. Ce n'est pas ce qui se produit.

Une variable n'est pas une boîte qui contient une valeur, c'est une étiquette collée sur un objet. Deux étiquettes peuvent désigner le même objet, ce qui arrive dès qu'une liste est passée à une fonction. Ce que del décolle, c'est l'étiquette.

PYTHON
a = [1, 2, 3]
b = a          # deux noms, un seul objet

del a
print(b)       # [1, 2, 3] : l'objet vit toujours

Le nom a a quitté l'espace courant, et le réutiliser déclenche une NameError. L'objet, lui, se porte bien, puisque b le désigne encore.

Cette instruction gère donc les noms, pas la mémoire. Python compte les références qui pointent vers chaque objet et rend la place quand ce compteur retombe à zéro : effacer la dernière référence libère bien l'objet, mais c'est une conséquence, jamais une promesse.

Bon à savoir

À ne pas confondre avec __del__, la méthode magique appelée au moment où un objet est réellement détruit. L'instruction del ne la déclenche que si elle supprime la dernière référence.


Ce qu'il efface selon la cible

La même instruction couvre cinq écritures. Ce qui change d'une ligne à l'autre n'est pas l'effet, assez prévisible, mais la façon d'échouer : c'est la colonne à lire en premier quand la cible vient d'un fichier ou du réseau.

ÉcritureEffetSi la cible manque
del nomRetire le nom de l'espace courantNameError
del liste[2]Retire l'élément de rang 2IndexError
del liste[1:3]Retire une tranche entièreRien, la tranche est tolérante
del dico["cle"]Retire la paire clé et valeurKeyError
del objet.attributRetire l'attribut de l'instanceAttributeError

La ligne des tranches détonne : une tranche (slicing) ne réclame pas un rang précis mais ce qui se trouve entre deux bornes. Quand cette zone est vide, il n'y a rien à retirer, donc rien à signaler.

Une limite manque au tableau : la cible doit être mutable. Sur un objet immuable, une chaîne ou un tuple, retirer un élément est refusé par un TypeError. Effacer le nom entier reste possible, sans toucher au contenu.

Reste la portée : dans une fonction, effacer une variable définie à l'extérieur suppose de la déclarer global au préalable, faute de quoi Python vise la variable locale du même nom et se plaint qu'elle n'existe pas.


del, pop, remove et clear

Quatre outils retirent des éléments d'une liste, et chacun répond à une demande différente.

OutilCe qu'il demandeCe qu'il rend
del liste[i]Un rangRien
liste.pop(i)Un rangL'élément retiré
liste.remove(v)Une valeurRien, et seule la première occurrence part
liste.clear()RienRien, la liste est vidée sur place

Le choix tient à ce que vous comptez faire de l'élément. S'il vous sert encore, pop vous le rend au passage ; sinon, del dit exactement cela, sans laisser croire qu'une valeur est récupérée quelque part.

Sur un dictionnaire, pop accepte en plus une valeur de repli, souvent None, renvoyée quand la clé manque au lieu d'une KeyError : la version indulgente, pour des clés dont l'absence n'a rien d'anormal.


Le piège de la suppression pendant un parcours

Ce dernier point envoie beaucoup de monde chercher de l'aide, et pour une raison précise : le programme ne plante pas, il rend un résultat faux. Retirer des éléments d'une liste pendant qu'on la parcourt décale les rangs sous les pieds de la boucle. Quand l'élément de rang 1 disparaît, l'ancien rang 2 glisse en rang 1, mais la boucle demande le rang 2, et l'élément qui vient de glisser n'est jamais examiné.

PYTHON
nombres = [1, 2, 2, 3]

# Faux : la liste change pendant le parcours
for i, n in enumerate(nombres):
    if n == 2:
        del nombres[i]
# [1, 2, 3] : un 2 a survécu

# Juste : reconstruire plutôt que retirer
nombres = [n for n in nombres if n != 2]

Un 2 a survécu et rien ne l'a signalé. Sur quatre éléments l'anomalie se voit ; sur dix mille lignes, elle part en production et se découvre le jour où un total ne tombe pas juste.

Attention

Ne modifiez jamais une liste pendant que vous la parcourez. Construisez la liste voulue avec une compréhension de liste, comme dans la seconde moitié de l'exemple : le résultat est exact et se relit sans effort.

Les dictionnaires sont plus francs : modifier leur taille en cours d'itération lève une exception immédiate au lieu de sauter des entrées en silence. Reconstruire reste de toute façon plus simple à relire qu'un parcours à rebours, l'autre solution classique.


Questions fréquentes

Question

del libère-t-il de la mémoire ?

Pas directement. Il retire une référence, et la place n'est rendue que lorsque la dernière disparaît. Sur un objet rangé dans une autre liste, la mémoire reste occupée comme avant et l'objet demeure accessible par son autre nom.

Question

Peut-on supprimer plusieurs choses en une ligne ?

Oui, en séparant les cibles par des virgules : del a, b, stock["poires"] efface les trois. Elles sont traitées de gauche à droite, et c'est là qu'il faut être prudent. Si la deuxième échoue, la première est déjà partie et la troisième ne sera jamais atteinte.

Question

Faut-il effacer ses variables en fin de traitement ?

Rarement. Les variables locales disparaissent d'elles-mêmes à la sortie de la fonction, et un usage systématique alourdit la lecture. Deux cas le justifient : un très gros objet qu'on veut cesser de retenir pendant un traitement long, et un nom réutilisé plus bas dont on veut interdire la relecture par erreur.

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.