I don’t think in this way you get a singleton, in a strict sense.
That’s just reflexivity of the is operation. Same true for any object:
>>> boo = object()
>>> boo is boo
True
Your nan won’t be unique, just as shown above — arithmetic operations or mathematical functions will turn it to some other object with a different identity:
>>> import math
>>> from math import nan
>>> -nan
nan
>>> nan is -nan # here it can't be same object, per IEEE 754
False
>>> math.sin(nan) is nan
False
The point is that you don’t get a singleton in this way. All you shown us is just a reflexivity property for a particular Python object. But that holds for any object, not just for a particular math.nan.
There can’t be “just one nan”. At least -nan must be a distinct object.
And the significance of this is that if x is nan: will never be a safe way to test for nan. Using math.nan might be more convenient than float("nan") when you’re assigning to it, but it’s no help with comparisons. The correct way to test for nanness is to see if it’s not equal to itself, and that doesn’t need anything from the math module.
And that manifests us, that it’s not a true singleton object.
Assuming you know type of the tested variable. If it’s not a float, well, nothing prevent us from inventing some other object with silly property wrt to equality (breaking reflexivity). Mathematica has, for example, the Indeterminate object, like a NaN in some sense:
In[1]:= Needs["ComputerArithmetic`"]
In[2]:= NaN == NaN
Out[2]= False
In[3]:= NaN === NaN
Out[3]= True
In[4]:= Indeterminate
Out[4]= Indeterminate
In[5]:= Indeterminate == Indeterminate
Out[5]= Indeterminate == Indeterminate
In[6]:= Indeterminate === Indeterminate
Out[6]= True
In[7]:= TrueQ[Indeterminate == Indeterminate]
Out[7]= False
That’s true, but I would argue that the IEEE floating point definition is so well-known at this point that anyone who’s making an object that isn’t equal to itself is deliberately evoking nan-like behaviour. Notably, the Indeterminate docs stipulates that, just like with NaN, operations on Indeterminate produce Indeterminate, and also like NaN, it represents not a single value but all possible values. So if you pass this to a naive “isnan()” function and it returns True, I would say that it’s not incorrect.
I’d say that it’s much more common for singletons to be used to ensure something, such as making sure there’s only one event loop. It isn’t just a performance question.
But there’s a lot of dispute about the true meaning of that word, and whether “globally unique instance” is the same thing, or if it only counts when the constructor returns the same instance again.
Lets ignore now, that this doesn’t play nicely with the standard.
Then yes, you can do that. Just remember, that underlying hardware arithmetic has different NaN’s and this affects results of arithmetic operations and libm functions.
You have to “canonicalize” hardware NaN’s somehow, say pick positive quiet NaN with no payload. The repr() behavior for CPython’s float’s may give you an illusion, that it’s already the case:
>>> float('nan')
nan
>>> -_ # no visual difference
nan
Yet you can reveal the difference, using some library functions like math.copysign() or unpacking values by the struct module. BTW, the Decimal’s play here more nicely: