Python:为何不支持列表与元组的比较?
当你把一个元组和一个列表进行比较,比如...
>>> [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中,每种数据都有特定的类型,而不是随便用的。很多人(大多数人?)都喜欢这种方式。