Why "is None" work faster than "== None"
First, we should know for a certainty that "is None" work faster cthan "== None":
>>> timeit.timeit("1 is None", number=10000000)
0.4035069934390217
>>> timeit.timeit("1 == None", number=10000000)
0.8190256083633187
Here is the Python source code implementing comparisons (is, ==, <=, etc.):
static PyObject *
cmp_outcome(int op, register PyObject *v, register PyObject *w)
{
int res = 0;
switch (op) {
case PyCmp_IS:
res = (v == w);
break;
...
default:
return PyObject_RichCompare(v, w, op);
is is implemented in just one line of code, a simple C pointer comparison. Some Python primitives compare equal according to this (because of interning, or because they are singletons like True, False and None).
On the other hand, eq uses PyObject_RichCompare, which is implemented with the helper function
richcmpfunc f;
PyObject *res;
int checked_reverse_op = 0;
if (v->ob_type != w->ob_type &&
PyType_IsSubtype(w->ob_type, v->ob_type) &&
(f = w->ob_type->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if ((f = v->ob_type->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
This checks the argument types and potentially tries multiple comparison functions (eq methods) before it can determine the answer. The comparison methods might do unlimited work (e.g. list.eq has to check each element of the lists, possibly recursively), but even in the simple case of x == None, the type checks and all the extra work will amount to a real slowdown compared to is.
Based on this SO topic and especially on this answer