is porównuje tożsamość obiektów (czy zmienne wskazują na ten sam obszar pamięci).== (operator eq) porównuje wartości, czyli czy obiekty są równe z punktu widzenia ich zawartości.is należy stosować do porównania tożsamości (np. z None lub dla obiektów singletonowych), a nie do sprawdzania równości wartości.
Przykład:
a = [1, 2, 3] b = [1, 2, 3] print(a == b) # True print(a is b) # False c = None d = None print(c is d) # True
Przy pracy z małymi liczbami całkowitymi lub ciągami interpreter może używać "internowania" (cached objects), co czasami sprawia, że is jest prawdziwe dla równych wartości, ale nie powinno to być stosowane w logice programu.
Pytanie: Co wyświetli następujący kod?
a = 256 b = 256 print(a is b) c = 257 d = 257 print(c is d)Dlaczego?
Odpowiedź:
Dla wartości od -5 do 256 Python używa puli liczb całkowitych. Wartości w tym zakresie zawsze wskazują na te same obiekty, dlatego a is b da True. 257 jest już poza pulą, więc c is d będzie False (obiekty są niezależne).
Historia
W jednym mikroserwisie porównanie równości ciągów przeprowadzono za pomocą is zamiast ==. Z powodu optymalizacji interpretera program działał "stabilnie" w testach, ale zaczął mieć błędy po rekompilacji lub innych zmianach środowiska.
Pewien programista do porównania liczb używał operatora is zamiast ==. Działało to dla małych liczb (dzięki puli), ale dla dużych — dawało błędy i nieprzewidywalne wyniki, co spowodowało niepoprawne działanie obliczeń.
W projektowaniu systemu autoryzacji sprawdzano przychodzący JSON za pomocą is None (poprawnie), a następnie analogicznie zrobiono to dla ciągów: if status is "ok". Okazało się to błędem — czasami warunek nie był spełniony, prowadząc do błędnej logiki przetwarzania danych.