x is None, not x == None (and NaN isn't equal to itself)
Two small Python habits head off a surprising number of bugs.
Use is for the singletons. is tests object identity — the same object in memory. == tests value, by calling __eq__, which any type is free to redefine. For None, True, and False, each a unique singleton, you want identity:
x is None x is not None x is FalseNever write x == None. With a plain value it happens to work, but == dispatches through __eq__, and that can do anything. A NumPy array compared to None does an elementwise comparison and then raises when the result is used in a boolean context; pandas and SQLAlchemy have their own __eq__ quirks. x is None is the one form that always means exactly what it looks like — which is why every linter flags == None.
Use == for actual values: n == 0, s == "foo", arr == other. The whole rule is: identity for the singletons, equality for everything else.
NaN is not equal to itself. By IEEE 754 a NaN compares unequal to everything, itself included:
>>> float("nan") == float("nan")
FalseSo any NaN check written with == silently fails: x == float("nan") is always False, even when x is NaN. To detect NaN, use
import math
math.isnan(x)or the shorthand x != x, which is True exactly when x is NaN.
And don't try to bridge the two ideas with x is float("nan"). float("nan") builds a fresh object on every call, so the identity check fails for a different reason than the equality one — two NaNs are neither == nor is. Only math.isnan (or x != x) actually works.