2

Even if those comparisons are not meaningful, why

list() == 1 
#return: False

but

list() > 1
#return: '>' not supported between instances of 'list' and 'int'

For me the two comparison operators should have the same behaviour, but it's not the case. I'm using Python 3.7 by the way.

Boann
  • 48,794
  • 16
  • 117
  • 146
obchardon
  • 10,614
  • 1
  • 17
  • 33
  • 1
    `list() == 1` can be used for `True` test (in this case to know if the list is empty or not) while `>` cannot. – dcg Jul 21 '19 at 15:11
  • `>` also produces a truth test... You can't know if a list is empty or not by comparing it to an int – Tomerikoo Jul 21 '19 at 15:12
  • 1
    What answer were you expecting `list() > 1` to have? In Python 2.x, that would actually work, but the result was arbitrary and meaningless. – jasonharper Jul 21 '19 at 15:12
  • @jasonharper I expected nothing, it just didn't get why the first case `list() == 1` got a result. – obchardon Jul 21 '19 at 15:15
  • How do you *expect* a list and an integer to be ordered in comparison to each other? If you don't have any expectation, why do you expect it to be possible? By contrast, mere equality doesn't require ordering; if things are of types that can't be compared for ordering purposes, it's very safe to say that they aren't equal without doing any further work. – Charles Duffy Jul 21 '19 at 15:16
  • Not duplicative, but closely related (insofar as the reasoning behind the answers there applies to the question here): [Can I make Python throw an exception when equal comparing different data types?](https://stackoverflow.com/questions/15451472) – Charles Duffy Jul 21 '19 at 15:18
  • 1
    @dcg so `[2] == 1` and `list() == 1` should give two differentes result, respectively `True` and `False` ? But both give `False`, so I don't get how it can be used to test if the list is empty or not. – obchardon Jul 21 '19 at 15:19
  • 2
    dcg must have been thinking about `len(list()) == 1`. Comparing a list to an integer will *always* be false, and never be meaningful. – Charles Duffy Jul 21 '19 at 15:21
  • @obchardon I was about to say that. I think the `==` is trying to compare the objects, since a `list` is not equal to `1` it's always `False`. – dcg Jul 21 '19 at 15:22
  • 2
    [Why does equality comparing an int with a string not throw an error?](https://stackoverflow.com/questions/10617737/), by contrast, I could argue actually works as a duplicate; it's a different incompatible type, sure, but the principals are identical. – Charles Duffy Jul 21 '19 at 15:23
  • BTW, [How does Python 2 compare string and int? Why do lists compare as greater than numbers, and tuples greater than lists?](https://stackoverflow.com/questions/3270680) explores the consequences of the prior, Python 2 behavior -- which goes some distance towards explaining why this behavior has been changed for Python 3. – Charles Duffy Jul 21 '19 at 15:26
  • @CharlesDuffy Thanks, the related question also answer this question. I will delete this post. Sorry for the duplicate. – obchardon Jul 21 '19 at 15:31

1 Answers1

1

This behavior can be seen in the implementation of object.c:

/* Perform a rich comparison, raising TypeError when the requested comparison
   operator is not supported. */
static PyObject *
do_richcompare(PyObject *v, PyObject *w, int op)
{
    // (omitted some code for brevity)

    /* If neither object implements it, provide a sensible default
       for == and !=, but raise an exception for ordering. */
    switch (op) {
    case Py_EQ:
        res = (v == w) ? Py_True : Py_False;
        break;
    case Py_NE:
        res = (v != w) ? Py_True : Py_False;
        break;
    default:
        PyErr_Format(PyExc_TypeError,
                     "'%s' not supported between instances of '%.100s' and '%.100s'",
                     opstrings[op],
                     v->ob_type->tp_name,
                     w->ob_type->tp_name);
        return NULL;
    }
    Py_INCREF(res);
    return res;
}

Looking at the commit that introduced this change it seems there was an intentional decision to only support equality and not support comparison for objects of different types.

To quote the summary lines from the commit message:

Restructure comparison dramatically. There is no longer a default ordering between objects; there is only a default equality test (defined by an object being equal to itself only).

...whereafter the message goes on to describe rationale (and some of the drawbacks to this change).

Kevin Ji
  • 10,479
  • 4
  • 40
  • 63
  • “This seems reasonable” — kind of not really. In fact, not at all. The issue isn’t that ordering relations aren’t supported, it’s that equality relations between unrelated types *are*. These implicit conversions shouldn’t happen. The fact that Python allows them is bad. – Konrad Rudolph Jul 21 '19 at 15:41
  • What implicit conversions, Konrad? It's no different than `.equals()` in Java defaulting to reference equality in the absence of anything better. – John Kugelman Jul 21 '19 at 15:43
  • I removed my personal opinion from the answer as it was not really relevant to the question. – Kevin Ji Jul 21 '19 at 15:48
  • @JohnKugelman Java also performs an implicit conversion here (with potential additional implicit boxing). And Java is flawed in exactly the same way (and very few people hold up Java as an example of a type system with strong semantics). Defining equality between unrelated types is a source of bugs, and is never a useful feature (it makes working with heterogeneous lists slightly easier but this could be implemented differently). – Konrad Rudolph Jul 22 '19 at 19:25