Python:为何不支持列表与元组的比较?

32 投票
2 回答
18448 浏览
提问于 2025-04-15 19:47

当你把一个元组和一个列表进行比较,比如...

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

... Python 不会像比较 (1,2,3) == (1,2,3) 那样进行深度比较。

那么,这背后的原因是什么呢?是因为可变的列表随时都可以被改变(可能会有线程安全的问题)还是其他原因呢?

(我知道这个在 CPython 中是怎么实现的,所以请不要回答 在哪里,而是 为什么 这样实现。)

2 个回答

14

列表和元组之间不能直接比较,并没有技术上的原因,这完全是设计上的选择。为了证明这和线程安全没有关系,你可以把列表和其他列表进行比较:

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

允许用户直接比较列表和元组似乎是合理的,但这样就会引出其他问题:用户是否也可以比较列表和队列?那任何两个提供迭代器的对象呢?比如下面这个:

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

这事情很快就会变得复杂。语言设计者意识到了这个问题,于是选择通过不允许不同类型的集合直接比较来避免这个麻烦1

需要注意的是,简单的解决办法(从元组创建一个新列表并进行比较)虽然简单,但效率不高。如果你处理的是大量数据,使用下面的方法会更好:

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

这个方法的好处是可以在任何两个序列上工作,但复杂度明显增加。


1 我提到集合和不可变集合是个例外。还有其他一些我不太清楚的例外。语言设计者在原则上是比较严格的,但在实际应用中也会考虑灵活性。

35

你总是可以“转换”它

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

请记住,Python和JavaScript不一样,Python是强类型的语言。这意味着在Python中,每种数据都有特定的类型,而不是随便用的。很多人(大多数人?)都喜欢这种方式。

撰写回答