W komentarzu do tego pytania widziałem stwierdzenie, które zaleca użycie
result is not None
vs
result != None
Zastanawiałem się, na czym polega różnica i dlaczego jedno może być polecane bardziej niż drugie?
W komentarzu do tego pytania widziałem stwierdzenie, które zaleca użycie
result is not None
vs
result != None
Zastanawiałem się, na czym polega różnica i dlaczego jedno może być polecane bardziej niż drugie?
Odpowiedzi:
==
jest testem równości . Sprawdza, czy z prawej strony i lewa strona są równe obiektów (zgodnie z ich __eq__
lub __cmp__
metod).
is
jest testem tożsamości . Sprawdza, czy prawa i lewa strona są tym samym przedmiotem. Nie są wykonywane żadne wywołania metod, obiekty nie mogą wpływać na is
operację.
Używasz is
(i is not
) do singletonów, np. None
Tam, gdzie nie przejmujesz się przedmiotami, które mogłyby udawać, że None
jesteś lub gdzie chcesz chronić przed pękaniem przedmiotów podczas porównywania None
.
None
ma kilka metod i prawie żadnych atrybutów. Jeśli __eq__
test oczekiwał metody lub atrybutu, może się on nie powieść. def __eq__( self, other ): return self.size == other.size
. Na przykład pęknie, jeśli other
tak się stanie None
.
is
jest jak Java ==
. Python's ==
jest jak Java .equals()
. Oczywiście pomaga to tylko wtedy, gdy znasz Javę.
is
jest podobny ===
(bardzo równy) i odwrotnie is not
jest podobny !==
(nie do końca równy).
is not
to pojedynczy operator, czy po prostu neguje wynik is
podobny do wewnętrznego not foo is bar
?
Najpierw pozwól mi przejść przez kilka terminów. Jeśli chcesz tylko uzyskać odpowiedź na pytanie, przewiń w dół do „Odpowiedzi na pytanie”.
Tożsamość obiektu : Kiedy tworzysz obiekt, możesz przypisać go do zmiennej. Następnie możesz przypisać ją do innej zmiennej. I kolejny.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
W tym przypadku cancel
, close
i dismiss
wszystkie odnoszą się do tego samego obiektu w pamięci. Utworzyłeś tylko jeden Button
obiekt, a wszystkie trzy zmienne odnoszą się do tego jednego obiektu. Mówimy, że cancel
, close
i dismiss
wszystkie odnoszą się do identycznych obiektów; to znaczy odnoszą się do jednego obiektu.
Równość obiektów : porównując dwa obiekty, zwykle nie przejmujesz się, że odnosi się to dokładnie do tego samego obiektu w pamięci. Dzięki równości obiektów możesz zdefiniować własne reguły porównywania dwóch obiektów. Kiedy piszesz if a == b:
, zasadniczo mówisz if a.__eq__(b):
. Umożliwia to zdefiniowanie __eq__
metody, a
dzięki czemu można użyć własnej logiki porównywania.
Uzasadnienie: dwa obiekty mają dokładnie takie same dane, ale nie są identyczne. (Nie są tym samym obiektem w pamięci.) Przykład: Ciągi znaków
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Uwaga: Używam tutaj ciągów znaków Unicode, ponieważ Python jest wystarczająco inteligentny, aby ponownie używać zwykłych ciągów bez tworzenia nowych w pamięci.
Tutaj mam dwa ciągi Unicode a
i b
. Mają dokładnie taką samą treść, ale nie są tym samym obiektem w pamięci. Jednak porównując je, chcemy, aby były one równe. To, co się tutaj dzieje, polega na tym, że obiekt Unicode zaimplementował tę __eq__
metodę.
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Uwaga: __eq__
on unicode
jest zdecydowanie zaimplementowany bardziej wydajnie niż to.
Uzasadnienie: Dwa obiekty mają różne dane, ale są uważane za ten sam obiekt, jeśli niektóre kluczowe dane są takie same. Przykład: większość typów danych modelu
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Tutaj mam dwa monitory Dell a
i b
. Mają tę samą markę i model. Nie mają one jednak tych samych danych ani nie są tym samym obiektem w pamięci. Jednak porównując je, chcemy, aby były one równe. W tym przypadku obiekt Monitor zaimplementował tę __eq__
metodę.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
Porównując do None
, zawsze używaj is not
. W Pythonie żaden nie jest singletonem - w pamięci jest tylko jedno jego wystąpienie.
Porównując tożsamość , można to zrobić bardzo szybko. Python sprawdza, czy obiekt, do którego się odwołujesz, ma taki sam adres pamięci jak globalny obiekt None - bardzo, bardzo szybkie porównanie dwóch liczb.
Porównując równość , Python musi sprawdzić, czy twój obiekt ma __eq__
metodę. Jeśli nie, bada każdą nadklasę szukającą __eq__
metody. Jeśli je znajdzie, Python go wywołuje. Jest to szczególnie złe, jeśli __eq__
metoda jest powolna i nie wraca natychmiast, gdy zauważy, że jest inny obiekt None
.
Nie wdrożyłeś __eq__
? Wówczas Python prawdopodobnie znajdzie __eq__
metodę object
i zastosuje ją zamiast tego - i tak po prostu sprawdza tożsamość obiektu.
Porównując większość innych rzeczy w Pythonie, będziesz używać !=
.
Rozważ następujące:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
None
jest singletonem, dlatego porównanie tożsamości zawsze będzie działać, podczas gdy obiekt może sfałszować porównanie równości za pomocą .__eq__()
.
None
, ale niewłaściwe zachowanie None
może wystąpić jako efekt uboczny wprowadzenia równości wobec innych typów. To nie tyle implikacje bezpieczeństwa, co implikacje poprawności.
>>> () jest () Prawdziwe >>> 1 to 1 Prawdziwe >>> (1,) == (1,) Prawdziwe >>> (1,) to (1,) Fałszywe >>> a = (1,) >>> b = a >>> a jest b Prawdziwe
Niektóre obiekty są singletonami, a zatem is
z nimi jest równoważne ==
. Większość nie.
()
i 1
nie są z natury singletonami.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) i puste krotki są singletonami. Rzeczywiście nie jest to udokumentowane ani gwarantowane, ale raczej nie ulegnie zmianie.