Czy istnieje różnica pomiędzy ==
oraz is
w Pythonie?
Tak, mają bardzo ważną różnicę.
==
: sprawdź równość - semantyka polega na tym, że równoważne obiekty (niekoniecznie te same obiekty) będą testować jako równe. Jak mówi dokumentacja :
Operatory <,>, ==,> =, <= i! = Porównują wartości dwóch obiektów.
is
: sprawdź tożsamość - semantyka polega na tym, że obiekt (przechowywany w pamięci) jest obiektem. Ponownie dokumentacja mówi :
Operatorzy is
i is not
testy do identyfikacji obiektu: x is y
jest prawdziwe wtedy i tylko wtedy x
, a y
to ten sam obiekt. Tożsamość obiektu określa się za pomocą id()
funkcji. x is not y
daje odwrotną wartość prawdy.
Zatem sprawdzenie tożsamości jest takie samo, jak sprawdzenie równości identyfikatorów obiektów. To jest,
a is b
jest taki sam jak:
id(a) == id(b)
gdzie id
jest wbudowana funkcja, która zwraca liczbę całkowitą, która „gwarantuje, że jest unikalna wśród jednocześnie istniejących obiektów” (patrz help(id)
) oraz gdzie a
i b
są dowolnymi obiektami.
Inne wskazówki użytkowania
Powinieneś używać tych porównań dla ich semantyki. Służy is
do sprawdzania tożsamości i ==
równości.
Ogólnie rzecz biorąc, używamy is
do sprawdzania tożsamości. Jest to zwykle przydatne, gdy szukamy obiektu, który powinien istnieć tylko raz w pamięci, zwany w dokumentacji „singletonem”.
Przypadki użycia is
obejmują:
None
- wartości wyliczeniowe (przy użyciu wyliczeń z modułu wyliczeniowego)
- zwykle moduły
- zwykle obiekty klasy wynikające z definicji klas
- zwykle obiekty funkcyjne wynikające z definicji funkcji
- wszystko inne, co powinno istnieć tylko raz w pamięci (ogólnie wszystkie singletony)
- konkretny obiekt, który chcesz według tożsamości
Typowe przypadki użycia ==
obejmują:
- liczby, w tym liczby całkowite
- smyczki
- listy
- zestawy
- słowniki
- niestandardowe obiekty zmienne
- inne wbudowane niezmienne obiekty, w większości przypadków
Ogólny przypadek użycia, znowu, dla ==
, jest przedmiotem chcesz nie może być taki sam przedmiot, a nie może być równoważny jeden
Kierunki PEP 8
PEP 8, oficjalny przewodnik po języku Python dla standardowej biblioteki, wspomina również o dwóch przypadkach użycia dlais
:
Porównania z singletonami, takie jak, None
należy zawsze przeprowadzać z operatorami równości is
lub
is not
nigdy.
Uważaj też na pisanie, if x
kiedy naprawdę masz na myśli if x is not None
- np. Podczas testowania, czy zmienna lub argument, który domyślnie ma None
wartość, została ustawiona na inną wartość. Druga wartość może mieć typ (na przykład kontener), który może być fałszywy w kontekście logicznym!
Wnioskowanie o równości na podstawie tożsamości
Jeśli is
jest to prawda, równość zwykle można wywnioskować - logicznie, jeśli obiekt jest sam, to powinien on przetestować jako równoważny sam sobie.
W większości przypadków ta logika jest prawdziwa, ale opiera się na implementacji __eq__
specjalnej metody. Jak mówią doktorzy ,
Domyślne zachowanie dla porównania równości ( ==
i !=
) opiera się na tożsamości obiektów. Zatem porównanie równości wystąpień o tej samej tożsamości powoduje równość, a porównanie równości wystąpień o różnych tożsamościach powoduje nierówność. Motywacją dla tego domyślnego zachowania jest pragnienie, aby wszystkie obiekty były refleksyjne (tj. X to y oznacza x == y).
oraz w celu zachowania spójności zaleca:
Porównanie równości powinno być zwrotne. Innymi słowy, identyczne obiekty powinny się równać:
x is y
implikuje x == y
Widzimy, że jest to domyślne zachowanie niestandardowych obiektów:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
Przeciwne jest również zwykle prawda - jeśli coś nie jest równe, zwykle można wywnioskować, że nie są one tym samym przedmiotem.
Ponieważ testy równości można dostosować, wnioskowanie to nie zawsze jest prawdziwe dla wszystkich typów.
Wyjątek
Godnym uwagi wyjątkiem jest nan
- zawsze testuje się jako nie równy sobie:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Sprawdzanie tożsamości może być znacznie szybsze niż sprawdzanie równości (co może wymagać rekurencyjnego sprawdzania członków).
Ale nie można go zastąpić równością, w której można znaleźć więcej niż jeden obiekt jako równoważny.
Zauważ, że porównanie równości list i krotek zakłada, że tożsamość obiektów jest równa (ponieważ jest to szybka kontrola). Może to powodować sprzeczności, jeśli logika jest niespójna - tak jak w przypadku nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Przestroga:
Pytanie próbuje użyć is
do porównania liczb całkowitych. Nie należy zakładać, że wystąpienie liczby całkowitej jest tym samym wystąpieniem, co wystąpienie innego odwołania. Ta historia wyjaśnia, dlaczego.
Komentator miał kod, który polegał na tym, że małe liczby całkowite (od -5 do 256 włącznie) są singletonami w Pythonie, zamiast sprawdzania równości.
Wow, może to prowadzić do pewnych podstępnych błędów. Miałem kod, który sprawdzał, czy a jest b, co działało tak, jak chciałem, ponieważ aib są zwykle małymi liczbami. Błąd pojawił się dopiero dzisiaj, po sześciu miesiącach produkcji, ponieważ aib były w końcu wystarczająco duże, aby nie zostać zbuforowane. - gwg
Działało w rozwoju. Być może minęło trochę nieprzyzwoitych wydarzeń.
I działało w produkcji - dopóki kod nie sprawdził liczby całkowitej większej niż 256, w którym momencie nie powiodło się w produkcji.
Jest to błąd produkcyjny, który mógł zostać wykryty podczas przeglądania kodu lub ewentualnie za pomocą narzędzia sprawdzającego styl.
Podkreślę: nie używaj is
do porównywania liczb całkowitych.
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
wyjście:False True False
.