Python: Почему сравнение между списками и кортежами не поддерживается? - PullRequest
20 голосов
/ 27 февраля 2010

При сравнении кортежа со списком вроде ...

>>> [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 ]

22 голосов
/ 27 февраля 2010

Вы всегда можете «разыграть» его

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

Имейте в виду, что Python, в отличие, например, от Javascript, строго напечатан , и некоторые (большинство?) Из нас предпочитают это так.

10 голосов
/ 27 февраля 2010

Нет технической причины, по которой списки нельзя сравнивать с кортежами; это полностью дизайнерское решение, основанное на семантике. Чтобы убедиться, что это не связано с безопасностью потоков, вы можете сравнить списки с другими списками:

>>> 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 Замечу, что есть исключение для наборов и морозилок. И, без сомнения, несколько других, о которых я не знаю. Разработчики языка - пуристы, за исключением тех случаев, когда это целесообразно.

...