2010-02-26 13 views
17

Porównując krotki z listy jak ...Python: Dlaczego porównanie list i krotek nie jest obsługiwane?

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

... Python nie głęboko porównać je jako wykonane z (1,2,3) == (1,2,3).

Jaki jest tego powód? Czy to dlatego, że zmieniającą się listę można zmienić w dowolnym momencie (problemy z bezpieczeństwem wątków) lub co?

(wiem, gdzie to jest realizowane w CPython, więc proszę nie odpowiadaj gdzie, ale dlaczego jest to realizowane.)

+4

Lista nie jest krotką i odwrotnie. Są to różne typy. '[] ==()' zwróci 'Fałsz'. – jathanism

+0

Zobacz też: http://stackoverflow.com/questions/12135264/what-are-the-best-ways-to-compare-the-contents-of-two-list-like-objects/12135322#12135322 – Erik

Odpowiedz

19

Zawsze można "rzucić" to

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

Należy pamiętać, że Python, w przeciwieństwie do na przykład Javascript, is stronglytyped, a niektóre (większość?) Z nas wolą to w ten sposób.

+2

To naprawdę to najlepszy sposób. – jathanism

+2

Lubię myśleć, że większość z nas woli to w ten sposób. –

+0

Myślę, że ważna jest tu idea silnego pisania na klawiaturze, więc przyjmuję twoją odpowiedź jako poprawną. – AndiDog

7

Nie ma technicznej przyczyny, że listy nie mogą być porównywane z krotkami; jest to całkowicie decyzja projektowa oparta na semantykach. Na dowód, że nie jest to związane z wątku bezpieczeństwa, można porównać list do innych list:

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

Wydaje się rozsądne, aby użytkownicy mogli bezpośrednio porównać listy i krotki, ale potem kończy się z innymi pytania: czy użytkownik może porównywać listy i kolejki? A co z dwoma obiektami, które zapewniają iteratory? A co z poniższymi?

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

Bardzo szybko może się skomplikować. Projektanci języka rozpoznali problem i uniknęli go, po prostu uniemożliwiając różnym rodzajom zbierania porównywanie się bezpośrednio ze sobą .

Należy zauważyć, że proste rozwiązanie (tworzenie nowej listy z krotki i porównywanie jej) jest łatwe, ale nieefektywne. Jeśli pracujesz z dużą liczbą elementów, jesteś lepiej z czymś takim:

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 

Ma to tę zaletę, że pracuje nad dwoma sekwencjami, w oczywisty koszt złożoności.


Zauważam istnieje wyjątek dla zbiorów i frozensets. I bez wątpienia kilka innych, których nie znam. Projektanci języków są purystami, chyba że opłaca się być praktycznym.

+0

+1 Bardzo dobre punkty, dzięki! – AndiDog

+3

Aby porównać dwie sekwencje, nie ma potrzeby przeskakiwania do następnych/StopIteracyjnych obręczy. wszystko (i1 == i2 dla i1, i2 w itertools.izip_longest (iter1, iter2, fillvalue = object())) –

Powiązane problemy