Python: Why is comparison between lists and tuples not supported?

Question:

When comparing a tuple with a list like …

>>> [1,2,3] == (1,2,3)
False
>>> [1,2,3].__eq__((1,2,3))
NotImplemented
>>> (1,2,3).__eq__([1,2,3])
NotImplemented

… Python does not deep-compare them as done with (1,2,3) == (1,2,3).

So what is the reason for this? Is it because the mutable list can be changed at any time (thread-safety issues) or what?

(I know where this is implemented in CPython, so please don’t answer where, but why it is implemented.)

Asked By: AndiDog

||

Answers:

You can always “cast” it

>>> tuple([1, 2]) == (1, 2)
True

Keep in mind that Python, unlike for example Javascript, is strongly typed, and some (most?) of us prefer it that way.

Answered By: Esteban Küber

There’s no technical reason for lists not being able to compare to tuples; it’s entirely a design decision driven by semantics. For proof that it’s not related to thread-safety, you can compare lists to other lists:

>>> l1 = [1, 2, 3]
>>> l2 = [1, 2, 3]
>>> l1 == l2
True
>>> id(l1) == id(l2)
False

It seems reasonable to allow users to directly compare lists and tuples, but then you end up with other questions: should the user be allowed to compare lists and queues? What about any two objects which provide iterators? What about the following?

>>> s = set([('x', 1), ('y', 2)])
>>> d = dict(s)
>>> s == d  # This doesn't work
False

It can get complicated pretty quickly. The language designers recognized the issue, and avoided it by simply preventing different collection types from comparing directly with each other1.

Note that the simple solution (to create a new list from the tuple and compare them) is easy but inefficient. If you’re working with large numbers of items, you’re better off with something like:

def compare_sequences(iter1, iter2):
    iter1, iter2 = iter(iter1), iter(iter2)
    for i1 in iter1:
        try:
            i2 = next(iter2)
        except StopIteration:
            return False

        if i1 != i2:
            return False

    try:
        i2 = next(iter2)
    except StopIteration:
        return True

    return False

This has the advantage of working on any two sequences, at an obvious cost in complexity.


1 I note there’s an exception for sets and frozensets. And no doubt a few others I’m not aware of. The language designers are purists, except where it pays to be practical.

Answered By: Chris B.
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.