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).
isjest 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 isoperację.
Używasz is(i is not) do singletonów, np. NoneTam, gdzie nie przejmujesz się przedmiotami, które mogłyby udawać, że Nonejesteś lub gdzie chcesz chronić przed pękaniem przedmiotów podczas porównywania None.
Nonema 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 othertak się stanie None.
isjest jak Java ==. Python's ==jest jak Java .equals(). Oczywiście pomaga to tylko wtedy, gdy znasz Javę.
isjest podobny ===(bardzo równy) i odwrotnie is notjest podobny !==(nie do końca równy).
is notto pojedynczy operator, czy po prostu neguje wynik ispodobny 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, closei dismisswszystkie odnoszą się do tego samego obiektu w pamięci. Utworzyłeś tylko jeden Buttonobiekt, a wszystkie trzy zmienne odnoszą się do tego jednego obiektu. Mówimy, że cancel, closei dismisswszystkie 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, adzię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 ai 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 unicodejest 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 ai 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ę objecti 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)
Nonejest 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 Nonemoż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 isz nimi jest równoważne ==. Większość nie.
()i 1nie 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.