Em um comentário sobre essa pergunta , vi uma declaração que recomendava o uso de
result is not None
vs
result != None
Eu queria saber qual é a diferença, e por que um pode ser recomendado em detrimento do outro?
Em um comentário sobre essa pergunta , vi uma declaração que recomendava o uso de
result is not None
vs
result != None
Eu queria saber qual é a diferença, e por que um pode ser recomendado em detrimento do outro?
Respostas:
==
é um teste de igualdade . Ele verifica se o lado direito e o lado esquerdo são iguais objectos (de acordo com as suas __eq__
ou __cmp__
métodos.)
is
é um teste de identidade . Ele verifica se o lado direito e o lado esquerdo são o mesmo objeto. Nenhuma chamada de método é feita, os objetos não podem influenciar a is
operação.
Você usa is
(e is not
) para singletons, como None
, onde você não se importa com objetos que possam querer fingir estar None
ou onde deseja proteger contra objetos quebrados ao serem comparados None
.
None
tem poucos métodos e quase nenhum atributo. Se o seu __eq__
teste esperava um método ou atributo, ele pode quebrar. def __eq__( self, other ): return self.size == other.size
. Por exemplo, irá quebrar se other
acontecer None
.
is
é como o Java ==
. O Python ==
é como o Java .equals()
. Claro que isso só ajuda se você conhece Java.
is
é como ===
(muito igual) e, inversamente, is not
é como !==
(não é exatamente igual).
is not
um único operador ou está apenas negando o resultado de is
gostar internamente not foo is bar
?
Primeiro, deixe-me passar por alguns termos. Se você apenas deseja que sua pergunta seja respondida, role para baixo até "Respondendo a sua pergunta".
Identidade do objeto : ao criar um objeto, você pode atribuí-lo a uma variável. Você também pode atribuí-lo a outra variável. E outro.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
Neste caso, cancel
, close
, e dismiss
todos se referem ao mesmo objeto na memória. Você criou apenas um Button
objeto e todas as três variáveis se referem a esse único objeto. Dizemos que cancel
, close
e dismiss
todos se referem a idênticas objetos; isto é, eles se referem a um único objeto.
Igualdade de objetos : quando você compara dois objetos, geralmente não se importa que se refira exatamente ao mesmo objeto na memória. Com a igualdade de objetos, você pode definir suas próprias regras para comparar dois objetos. Quando você escreve if a == b:
, você está dizendo essencialmente if a.__eq__(b):
. Isso permite definir um __eq__
método ema
para que você possa usar sua própria lógica de comparação.
Justificativa: Dois objetos têm exatamente os mesmos dados, mas não são idênticos. (Eles não são o mesmo objeto na memória.) Exemplo: Strings
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Nota: Eu uso cadeias unicode aqui porque o Python é inteligente o suficiente para reutilizar cadeias regulares sem criar novas na memória.
Aqui, eu tenho duas cadeias unicode, a
e b
. Eles têm exatamente o mesmo conteúdo, mas não são o mesmo objeto na memória. No entanto, quando os comparamos, queremos que eles comparem iguais. O que está acontecendo aqui é que o objeto unicode implementou o __eq__
método.
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
Nota: __eq__
on unicode
é definitivamente implementado com mais eficiência do que isso.
Justificativa: Dois objetos têm dados diferentes, mas são considerados o mesmo objeto se alguns dados importantes forem os mesmos. Exemplo: a maioria dos tipos de dados do modelo
>>> 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
Aqui, tenho dois monitores Dell a
e b
. Eles têm a mesma marca e modelo. No entanto, eles não têm os mesmos dados nem o mesmo objeto na memória. No entanto, quando os comparamos, queremos que eles comparem iguais. O que está acontecendo aqui é que o objeto Monitor implementou o __eq__
método.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
Ao comparar com None
, use sempreis not
. Nenhum é um singleton em Python - existe apenas uma instância na memória.
Comparando a identidade , isso pode ser realizado muito rapidamente. O Python verifica se o objeto ao qual você está se referindo tem o mesmo endereço de memória que o objeto None global - uma comparação muito, muito rápida de dois números.
Ao comparar a igualdade , o Python precisa verificar se o seu objeto possui um __eq__
método. Caso contrário, examina cada superclasse procurando um __eq__
método. Se encontrar, Python o chama. Isso é especialmente ruim se o __eq__
método for lento e não retornar imediatamente quando perceber que o outro objeto estáNone
.
Você não implementou __eq__
? Então o Python provavelmente encontrará o __eq__
método object
e o utilizará - o que apenas verifica a identidade do objeto de qualquer maneira.
Ao comparar a maioria das outras coisas em Python, você estará usando !=
.
Considere o seguinte:
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
é um singleton, portanto, a comparação de identidade sempre funcionará, enquanto um objeto pode falsificar a comparação de igualdade via .__eq__()
.
None
, mas um comportamento incorreto None
pode ocorrer como um efeito colateral da implementação da igualdade contra outros tipos. Não são tantas implicações de segurança, mas apenas implicações de correção.
>>> () é () Verdade >>> 1 é 1 Verdade >>> (1,) == (1,) Verdade >>> (1,) é (1,) Falso >>> a = (1,) >>> b = a >>> a é b Verdade
Alguns objetos são singletons e, portanto, is
com eles é equivalente a ==
. A maioria não é.
()
e 1
não são inerentemente singletons.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) e as tuplas vazias são singletons. Na verdade, não está documentado nem garantido, mas é improvável que mude.