0

In Python2, it's valid:

#!/usr/bin/python

class ListNode(object):
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

a = ListNode(0)
b = ListNode(1)

print(a < b)

Output: True

But same code in Python3, it will raise exception:

#!/usr/bin/python3

class ListNode(object):
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

a = ListNode(0)
b = ListNode(1)

print(a < b)

Raise exception:

Traceback (most recent call last):
  File "c.py", line 11, in <module>
    print(a < b)
TypeError: '<' not supported between instances of 'ListNode' and 'ListNode'

Why it's different?


add:

I can add __lt__ method to ListNode to avoid the exception: ListNode.__lt__ = lambda a, b: id(a) - id(b).

But why there's no need for Python2 to add the __lt__ method?

3
  • In Python-3.x, you must implement the method __eq__ to compare objects. Commented Aug 28, 2020 at 5:08
  • 1
    @DYZ: Well, a default __eq__ is provided, it just compares by identity. __lt__ doesn't have a useful default, so you have to write it yourself. Commented Aug 28, 2020 at 5:13
  • @ShadowRanger My mistake, I meant __lt__ and __gt__. Commented Aug 28, 2020 at 5:13

1 Answer 1

5

In Python 2, when you lack __lt__ (or the older deprecated __cmp__), the default comparison rules kick in, which, in this case, eventually ends up comparing the memory addresses of the objects in question (before that, it's putting numbers before other stuff, and comparing everything else based on the string name of the class).

But this is almost never useful; if you haven't defined how to order instances of a class, arbitrarily ordering them by memory address (which changes each run) is silently misbehaving in 99% of code.

Python 3 fails loudly when that happens so people don't rely on sorting unsortable things by accident; if someone sorts [1, 'a', (), None] or even just a list of your instances with undefined ordering, raising an exception is just more helpful. If memory address ordering is really what's needed, you can always implement it like you did, but that's a vanishingly rare use case.

Sign up to request clarification or add additional context in comments.

7 Comments

Emm, it sounds reasonable. I understand why I have to implement methods such as __lt__, __le__ in Python3 now.
@Lane: Yar. You don't need to implement all of them yourself though. functools.total_ordering can be used as a decorator to turn just __eq__ and __lt__ into the full suite of rich comparison methods. Or you can write a newfangled dataclass and just tell it order=True so it makes the comparison methods for you.
You mean by id. Are you sure that this is always a memory address? In python2, if I create an empty list, and then in a loop I create alternating integers and strings and append them to the list, and then sort it, all the integers end up at the start before all the strings. In CPython 2, the ids for the ints are much smaller numbers than the ids for the strings. (Obviously when comparing two ints in the list, or two strings, it will use the actual value -- but I'm talking here about when it compares ints with strings.)
@alani: As I mentioned in the parenthetical, the default comparison rules only resort to comparing memory addresses after sorting things by their defined comparators when available, and the names of their types when they're not defined. It was an ugly, ugly mess, with lots of subtleties; it's just in the OP's case all the types are the same, so it ends up not mattering, and only the memory addresses count. CPython's id is the memory address (not necessarily the case in other interpreters, but the fallback sort wasn't a language defined behavior IIRC, just a CPython implementation detail).
@alani: Note: Even the "names of their types" thing is glossing over details (old-style and new-style classes wouldn't sort together, None sorts before everything else, numbers do sort together, etc.). Suffice to say, Python 2's fallback comparison was incredibly complicated, and died a well-deserved death. I'd like to let it rest in peace. :-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.