Existe uma diferença entre ==
e is
em Python?
Sim, eles têm uma diferença muito importante.
==
: verifique a igualdade - a semântica é que objetos equivalentes (que não são necessariamente o mesmo objeto) serão testados como iguais. Como a documentação diz :
Os operadores <,>, ==,> =, <= e! = Comparam os valores de dois objetos.
is
: verifique a identidade - a semântica é que o objeto (como mantido na memória) é o objeto. Mais uma vez, a documentação diz :
Os operadores is
e o is not
teste da identidade do objeto: x is y
são verdadeiros se e somente se x
e y
são o mesmo objeto. A identidade do objeto é determinada usando a id()
função x is not y
produz o valor inverso da verdade.
Portanto, a verificação de identidade é igual à verificação da igualdade dos IDs dos objetos. Isso é,
a is b
é o mesmo que:
id(a) == id(b)
onde id
é a função interna que retorna um número inteiro que "é garantido como único entre objetos existentes simultaneamente" (consulte help(id)
) e onde a
e b
quaisquer objetos arbitrários.
Outras instruções de uso
Você deve usar essas comparações para suas semânticas. Use is
para verificar a identidade e ==
verificar a igualdade.
Então, em geral, usamos is
para verificar a identidade. Isso geralmente é útil quando estamos verificando um objeto que deveria existir apenas uma vez na memória, chamado de "singleton" na documentação.
Casos de uso para is
incluir:
None
- valores de enum (ao usar enums do módulo enum)
- geralmente módulos
- geralmente objetos de classe resultantes de definições de classe
- objetos de função geralmente resultantes de definições de função
- qualquer outra coisa que deveria existir apenas uma vez na memória (todos os singletons, geralmente)
- um objeto específico que você deseja por identidade
Casos de uso usual para ==
incluem:
- números, incluindo números inteiros
- cordas
- listas
- conjuntos
- dicionários
- objetos mutáveis personalizados
- outros objetos imutáveis embutidos, na maioria dos casos
O caso de uso geral, de novo, para ==
, é o objeto que você quer pode não ser o mesmo objeto, em vez disso, pode ser um equivalente de um
Direções do PEP 8
O PEP 8, o guia de estilo oficial do Python para a biblioteca padrão também menciona dois casos de uso parais
:
As comparações com singletons como None
sempre devem ser feitas com is
ou
is not
, nunca com os operadores de igualdade.
Além disso, tenha cuidado ao escrever if x
quando você realmente quiser if x is not None
- por exemplo, ao testar se uma variável ou argumento cujo padrão None
é definido como outro valor. O outro valor pode ter um tipo (como um contêiner) que pode ser falso em um contexto booleano!
Inferindo a igualdade da identidade
Se is
for verdade, a igualdade geralmente pode ser inferida - logicamente, se um objeto é ele próprio, deve ser testado como equivalente a ele mesmo.
Na maioria dos casos, essa lógica é verdadeira, mas depende da implementação do __eq__
método especial. Como dizem os documentos ,
O comportamento padrão para comparação de igualdade ( ==
e !=
) é baseado na identidade dos objetos. Portanto, a comparação de igualdade de instâncias com a mesma identidade resulta em igualdade e a comparação de igualdade de instâncias com identidades diferentes resulta em desigualdade. Uma motivação para esse comportamento padrão é o desejo de que todos os objetos sejam reflexivos (ou seja, x é y implica x == y).
e no interesse da consistência, recomenda:
A comparação da igualdade deve ser reflexiva. Em outras palavras, objetos idênticos devem comparar iguais:
x is y
implica x == y
Podemos ver que este é o comportamento padrão para objetos personalizados:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
O contrapositivo também costuma ser verdadeiro - se algumas coisas não são iguais, você pode inferir que elas não são o mesmo objeto.
Como os testes de igualdade podem ser personalizados, essa inferência nem sempre é verdadeira para todos os tipos.
Uma exceção
Uma exceção notável é nan
- ele sempre testa como diferente de si mesmo:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Verificar a identidade pode ser muito mais rápido do que verificar a igualdade (o que pode exigir a verificação recursiva dos membros).
Mas não pode ser substituído por igualdade, onde você pode encontrar mais de um objeto como equivalente.
Observe que comparar a igualdade de listas e tuplas pressupõe que a identidade dos objetos seja igual (porque essa é uma verificação rápida). Isso pode criar contradições se a lógica for inconsistente - como é para nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Um conto de advertência:
A questão está tentando usar is
para comparar números inteiros. Você não deve assumir que uma instância de um número inteiro é a mesma instância que uma obtida por outra referência. Esta história explica o porquê.
Um comentarista tinha um código que se baseava no fato de que pequenos números inteiros (-5 a 256 inclusive) são singletons em Python, em vez de verificar a igualdade.
Uau, isso pode levar a alguns erros insidiosos. Eu tinha um código que verificava se a é b, que funcionava como eu queria, porque a e b são tipicamente pequenos números. O bug só aconteceu hoje, após seis meses de produção, porque aeb foram finalmente grandes o suficiente para não serem armazenados em cache. - gwg
Funcionou em desenvolvimento. Pode ter passado alguns unittests.
E funcionou na produção - até o código procurar um número inteiro maior que 256, quando falhou na produção.
Esta é uma falha de produção que poderia ter sido detectada na revisão de código ou possivelmente com um verificador de estilo.
Deixe-me enfatizar: não use is
para comparar números inteiros.
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
saída:False True False
.