None en Python : l'absence de valeur

None représente l'absence de valeur en Python : ni zéro, ni chaîne vide, ni False, mais un objet unique à tester avec is.
5 min de lecture
Believemy logo

Définition

Un programme rencontre sans cesse des moments où il n'a rien à mettre dans une variable : une recherche qui n'a rien trouvé, un champ de formulaire resté vide, un calcul pas encore fait. Zéro suggérerait un résultat chiffré, une chaîne vide suggérerait du texte manquant, mais il ne s'agit ni de l'un ni de l'autre : il n'y a tout simplement rien. Python répond à ce besoin avec None, un mot réservé qui signifie exactement cela.

Sous le capot, None est un objet unique dans tout le programme : où qu'il apparaisse, variable, argument ou résultat de fonction, c'est toujours le même exemplaire. Cette particularité détermine la bonne façon de le tester, expliquée plus bas.

PYTHON
resultat = None

if resultat is None:
    print("Pas encore calculé")

On le croise à quelques endroits précis. Une fonction sans return le renvoie automatiquement. Une recherche infructueuse le renvoie souvent, plutôt que de faire planter le programme. Et un argument optionnel laissé de côté vaut fréquemment None par défaut, un usage détaillé plus bas.


Ce qu'il n'est pas

La confusion la plus répandue range None avec les autres valeurs que Python considère comme fausses dans un test, au même titre que 0 ou qu'une liste vide. Une condition comme if not valeur: les traite pareil, mais elles ne racontent pas la même histoire.

Le tableau suivant les met côte à côte, une par une :

ValeurSens
NoneIl n'y a pas de valeur
0Il y a une valeur, et elle vaut zéro
""Il y a une chaîne, et elle est vide
FalseIl y a un booléen, et il est faux
[]Il y a une liste, et elle est vide

Cette différence n'a l'air que théorique jusqu'au jour où un zéro devient une réponse valable. Un compte bancaire affichant 0 n'est pas un compte au solde inconnu, et un champ de formulaire renvoyant une chaîne vide n'est pas un champ resté vierge. Confondre les deux ne casse rien tout de suite : le bug apparaît plus tard, sur un cas limite que personne n'avait anticipé.


Le tester avec is, jamais avec ==

Comment vérifier qu'une variable vaut None ? La tentation naturelle est d'écrire == None, comme pour toute autre comparaison, mais ce n'est pas la bonne question. Puisqu'il n'existe qu'un seul None dans tout le programme, il faut se demander non pas si la valeur est égale à None, mais si elle est None. La première interroge une valeur, avec == ; la seconde interroge une identité, avec is, et c'est elle qui donne toujours la bonne réponse.

La nuance reste invisible la plupart du temps, jusqu'au jour où un objet redéfinit sa méthode de comparaison : il peut alors répondre « oui » à == None sans être None pour autant, alors que l'identité ne se laisse pas usurper.

PYTHON
# Correct
if valeur is None:
    ...

# À éviter
if valeur == None:
    ...
Bon à savoir

PEP 8, le guide de style officiel du langage, recommande explicitement is None. Des outils comme ruff le signalent d'ailleurs comme une erreur de style dès qu'un == None traîne dans le code.


Le piège de l'argument par défaut

Un piège classique attend quiconque choisit une liste vide comme valeur par défaut : l'intention semble raisonnable, offrir à chaque appel une liste toute prête plutôt que d'obliger l'appelant à en fournir une.

PYTHON
# Piège : la même liste pour tout le monde
def ajouter(element, panier=[]):
    panier.append(element)
    return panier

Le problème tient à un détail d'exécution que peu anticipent : Python évalue la valeur par défaut une seule fois, à la définition de la fonction, pas à chaque appel. La liste créée ce jour-là reste donc partagée par tous les appels suivants, sans être réinitialisée, et grossit d'un appel à l'autre.

La correction : donner None par défaut, puis créer la vraie liste dans la fonction, seulement si elle manque.

PYTHON
# Correction : None comme sentinelle
def ajouter(element, panier=None):
    if panier is None:
        panier = []
    panier.append(element)
    return panier

C'est l'usage le plus répandu de None hors retour de fonction : une sentinelle qui dit « rien n'a été fourni », précisément parce qu'aucune valeur légitime ne peut lui ressembler par accident.

Attention

Le piège ne se limite pas aux listes : un dictionnaire vide ou un ensemble vide posent le même problème en valeur par défaut. La même solution, None puis création à l'intérieur de la fonction, s'applique aux trois.


Questions fréquentes

Question

Pourquoi ma fonction renvoie-t-elle None ?

Parce qu'elle ne comporte aucun return, ou qu'un chemin d'exécution particulier l'évite. C'est aussi le cas des méthodes qui modifient un objet sur place, comme sort : elles travaillent sur l'objet donné et ne renvoient rien.

Question

None est-il équivalent à null dans d'autres langages ?

L'intention est la même d'un langage à l'autre, mais l'implémentation diffère. None est un véritable objet, avec un type nommé NoneType, alors que null désigne souvent un pointeur vide. Cela signifie qu'on peut assigner None, le passer en argument et le comparer sans jamais risquer de faire planter le programme.

Question

Comment distinguer une clé absente d'une clé valant None ?

Avec in plutôt qu'un accès direct : if "cle" in mon_dico répond sur la présence de la clé, alors que lire sa valeur avec get renvoie None dans les deux cas. La distinction devient critique dès qu'on traite du json venu d'une source extérieure.

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.