For some reason in Python 2.7 expressions of the form tuple > list
return True
, but tuple < list
and tuple == list
return False
. Why is that?
This observation is not original to me by any means.
For some reason in Python 2.7 expressions of the form tuple > list
return True
, but tuple < list
and tuple == list
return False
. Why is that?
This observation is not original to me by any means.
tuple
and list
are not the same type. Python does something kind of surprising when comparing values that are not of the same type, and which don't define comparators that work across these types. it compares the dictionary order of the names of the classes:
>>> class Coffee(object):
... pass
...
>>> class Tea(object):
... pass
...
>>> c = Coffee()
>>> t = Tea()
>>> c > t
False
>>> c == t
False
>>> c < t
True
>>>
Thankfully, in python 3, this goes away, comparing such types raises an exception.
From the doc:
The operators
<
,>
,==
,>=
,<=
, and!=
compare the values of two objects. The objects need not have the same type. If both are numbers, they are converted to a common type. Otherwise, objects of different types always compare unequal, and are ordered consistently but arbitrarily.
Because python objects of different types are compared arbitrarily (arbitrarily means "alphabetically by their type name" at least in python 2.7). Therefore, a tuple
will always be >
then a list
.
The Python (2.7) Language Reference - 5.9. Comparisons:
Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
The rules for comparing objects of different types should not be relied upon; they may change in a future version of the language.
This is the c
function for comparing python objects (from the Python 2.7 source):
default_3way_compare(PyObject *v, PyObject *w)
{
int c;
const char *vname, *wname;
if (v->ob_type == w->ob_type) {
/* When comparing these pointers, they must be cast to
* integer types (i.e. Py_uintptr_t, our spelling of C9X's
* uintptr_t). ANSI specifies that pointer compares other
* than == and != to non-related structures are undefined.
*/
Py_uintptr_t vv = (Py_uintptr_t)v;
Py_uintptr_t ww = (Py_uintptr_t)w;
return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
}
/* None is smaller than anything */
if (v == Py_None)
return -1;
if (w == Py_None)
return 1;
/* different type: compare type names; numbers are smaller */
if (PyNumber_Check(v))
vname = "";
else
vname = v->ob_type->tp_name;
if (PyNumber_Check(w))
wname = "";
else
wname = w->ob_type->tp_name;
c = strcmp(vname, wname);
if (c < 0)
return -1;
if (c > 0)
return 1;
/* Same type name, or (more likely) incomparable numeric types */
return ((Py_uintptr_t)(v->ob_type) < (
Py_uintptr_t)(w->ob_type)) ? -1 : 1;
}
The main part to look at is the lines (towards the end):
else
wname = w->ob_type->tp_name;
c = strcmp(vname, wname);