NaN en Python : les bizarreries avec les dictionnaires et les sets NaN en Python crée des situations paradoxales dans les sets et les dictionnaires : il est hashable mais jamais égal à lui-même. NaN en Python est une valeur qui peut semer le doute dans le code.
NaN en Python est une valeur qui peut semer le doute dans le code. float('nan') échappe à l’égalité: il n’est égal à aucun autre NaN, y compris lui-même. Cette singularité, loin d’être théorique, a des répercussions concrètes sur les collections Python, notamment les sets et les dictionnaires. Comprendre ce comportement permet d’éviter des pièges courants lors de l’ingénierie de données ou lors de la gestion d’objets manquants.
NaN en Python et les fondements techniques
Le NaN vient des normes IEEE 754 et représente une valeur « Not a Number ». En Python, float('nan') est une instance de float qui, par conception, ne compare pas à aucune autre valeur. En pratique, NaN != NaN. Cette propriété fondamentale explique pourquoi NaN peut être reçu comme sensibilisant dans des scénarios mathématiques, tout en présentant une incohérence lorsque l’on parle d’égalité dans des structures de données.
Par ailleurs, NaN est hashable: il peut être utilisé comme clé dans un dictionnaire ou comme élément d’un set. Cela signifie qu’il peut exister des NaN distincts dans un même conteneur, chaque NaN étant traité comme un élément unique par rapport à l’égalité, car l’égalité entre NaN est toujours fausse.
Ce qui se passe exactement dans les sets et les dictionnaires
Dans un set, l’objectif est d’éviter les doublons. Comme NaN n’est égal à aucun NaN, y compris à lui-même, chaque NaN distinct peut être stocké séparément. Autrement dit, un ensemble peut contenir plusieurs occurrences de float('nan'), chacun étant considéré comme un élément différent malgré des valeurs d’appoint similaires.
Dans un dictionnaire, les clés dépendent aussi de l’égalité. On peut insérer plusieurs clés NaN dans le même dictionnaire, chacune restant distincte puisque leur égalité est toujours fausse. Cela peut conduire à un dictionnaire avec plusieurs entrées dont les clés ne se ressemblent pas et, surtout, à des accès peu fiables: tenter d’obtenir une valeur avec une clé float('nan') ne renverra généralement pas la valeur associée à une clé NaN différente, car NaN n’est égal à aucune autre NaN.
alice = float('nan')
bob = float('nan')
s = {alice, bob}
print(len(s)) # généralement 2, car alice != bob
d = {alice: 'premier', bob: 'second'}
print(len(d)) # généralement 2
try:
print(d[alice])
except KeyError:
print('Clé NaN introuvable avec NaN utilisée pour la recherche')
Bonnes pratiques et limites à connaître
Utiliser NaN comme clé dans un dictionnaire n’est pas recommandé. Si vous avez besoin d’un marqueur pour représenter une valeur manquante, privilégiez None ou une valeur sentinel bien définie. Certaines bibliothèques, comme pandas, gèrent les NaN dans des cadres spécifiques et clarifient leur sémantique, ce qui peut éviter des ambiguïtés en science des données.
Pour les sets, la présence de NaN peut être utile si vous avez besoin de repérer plusieurs instances distinctes de NaN. En revanche, si votre logique repose sur l’unicité des éléments, il vaut mieux filtrer les NaN ou les convertir en une valeur substitutive afin d’éviter des comportements inattendus lors des itérations ou des comparaisons.
Pour terminer
Ce que démontre NaN en Python, c’est qu’une valeur peut être hashable tout en échappant à l’égalité. Cette dualité oblige à tester les cas limites et à choisir des conventions claires lorsque l’on travaille avec des ensembles ou des dictionnaires susceptibles d’englober des NaN. La prudence reste de mise pour éviter des comportements difficiles à déboguer en production.