Existe uma diferença entre "==" e "is"?

630

Meu Google-fu falhou comigo.

No Python, os dois testes a seguir para igualdade são equivalentes?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

Isso vale para objetos em que você compararia instâncias ( listdigamos)?

Ok, então este tipo de resposta à minha pergunta:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

Então ==testa o valor de onde istesta para ver se eles são o mesmo objeto?

Bernard
fonte

Respostas:

928

isretornará Truese duas variáveis ​​apontarem para o mesmo objeto, ==se os objetos referidos pelas variáveis ​​forem iguais.

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

No seu caso, o segundo teste só funciona porque o Python armazena em cache pequenos objetos inteiros, o que é um detalhe de implementação. Para números inteiros maiores, isso não funciona:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

O mesmo vale para literais de cadeia de caracteres:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Por favor, veja esta pergunta também.

Torsten Marek
fonte
2
Descobri que: echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foosaída: False True False.
ahuigo
Você me perdeu com a b = a[:]parte de cópia da lista de operadores de fatias, por isso editei sua resposta para fazer um comentário lá. Parece que atingi o limite para não ter que revisar minhas edições antes de aplicá-las, por isso espero que seja legal com você. Independentemente disso, aqui é uma referência útil para saber como copiar listas que me deparei e teve de referência para descobrir o que estava fazendo: stackoverflow.com/a/2612815/4561887
Gabriel Staples
Outra maneira de demonstrar a diferença é comparando objetos de tipos diferentes, os quais, é claro, nunca podem ser o mesmo objeto, mas ainda se comparam da mesma forma quando usados ==. Por 5.0exemplo, é um valor de ponto flutuante, enquanto 5é um número inteiro. Mas 5.0 == 5ainda retornará Trueporque eles representam o mesmo valor. Em termos de desempenho e digitação de pato, issempre é testado pelo intérprete comparando os endereços de memória do operando, enquanto ==que cabe ao objeto decidir se ele se define como igual a outra coisa.
Bachsau
3
1000 is 10**3avalia a verdade em Python 3.7 desde 10 ** 3 é tipo int. Mas 1000 is 1e3avalia como False, pois 1e3 é do tipo float.
Ahmed Fasih 08/09/19
@AhmedFasih Se 1000 is 10**3é verdade ou não , depende da implementação e depende do compilador que pré-avalia a expressão 10**3. x=10; 1000 is x**3avalia como False.
chepner 27/05
313

Existe uma regra simples para dizer quando usar ==ou is.

  • ==é para igualdade de valor . Use-o quando desejar saber se dois objetos têm o mesmo valor.
  • isé para igualdade de referência . Use-o quando desejar saber se duas referências se referem ao mesmo objeto.

Em geral, quando você está comparando algo com um tipo simples, geralmente está verificando a igualdade de valor , portanto, você deve usá-lo ==. Por exemplo, a intenção do seu exemplo é provavelmente verificar se x tem um valor igual a 2 ( ==), não se xestá literalmente se referindo ao mesmo objeto que 2.


Algo mais a ser observado: devido à maneira como a implementação de referência CPython funciona, você obterá resultados inesperados e inconsistentes se usar por engano ispara comparar a igualdade de referência em números inteiros:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

É praticamente o que esperávamos: ae btêm o mesmo valor, mas são entidades distintas. Mas e isso?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

Isso é inconsistente com o resultado anterior. O que está acontecendo aqui? Acontece que a implementação de referência do Python armazena em cache objetos inteiros no intervalo -5..256 como instâncias singleton por motivos de desempenho. Aqui está um exemplo demonstrando isso:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

Esse é outro motivo óbvio para não usar is: o comportamento é deixado para implementações quando você o usa erroneamente para obter igualdade de valor.

John Feminella
fonte
Com relação ao primeiro exemplo de a=500e b=500, só queria salientar que se você definir ae bpara um interger entre [-5, 256], a is bna verdade retornará True. Mais informações aqui: stackoverflow.com/q/306313/7571052
AsheKetchum
1
@AsheKetchum, sim, observe que escrevi "Acontece que a implementação de referência do Python armazena em cache objetos inteiros no intervalo -5..256 como instâncias singleton por motivos de desempenho".
John Janella
34

==determina se os valores são iguais, enquanto isdetermina se eles são exatamente o mesmo objeto.

stephenbayer
fonte
32

Existe uma diferença entre ==e isem 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 ise o is notteste da identidade do objeto: x is ysão verdadeiros se e somente se xe ysão o mesmo objeto. A identidade do objeto é determinada usando a id()função x is not yproduz 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 ae bquaisquer objetos arbitrários.

Outras instruções de uso

Você deve usar essas comparações para suas semânticas. Use ispara verificar a identidade e ==verificar a igualdade.

Então, em geral, usamos ispara 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 isincluir:

  • 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 Nonesempre devem ser feitas com isou is not, nunca com os operadores de igualdade.

Além disso, tenha cuidado ao escrever if xquando 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 isfor 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 ispara 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 ispara comparar números inteiros.

Aaron Hall
fonte
"não usar é de todo" seria uma boa regra também. O idiomático is Noneé uma exceção, mas isso dito == Nonetambém funciona ...
Jean-François Fabre
@ Jean-FrançoisFabre Outra exceção: a documentação oficial parece recomendar o uso ispara comparar Enums.
Arthur
@Arthur Adicionei uma lista de casos de uso ...
Aaron Hall
19

Qual é a diferença entre ise ==?

==e issão diferentes comparação! Como outros já disseram:

  • == compara os valores dos objetos.
  • is compara as referências dos objetos.

No Python, os nomes se referem a objetos, por exemplo, neste caso, value1e value2a uma intinstância que armazena o valor 1000:

value1 = 1000
value2 = value1

insira a descrição da imagem aqui

Porque value2se refere ao mesmo objeto ise ==dará True:

>>> value1 == value2
True
>>> value1 is value2
True

No exemplo a seguir, os nomes value1e se value2referem a intinstâncias diferentes , mesmo que os dois armazenem o mesmo número inteiro:

>>> value1 = 1000
>>> value2 = 1000

insira a descrição da imagem aqui

Porque o mesmo valor (inteiro) é armazenado ==será True, por isso é muitas vezes chamado de "comparação de valor". No entanto is, retornará Falseporque estes são objetos diferentes:

>>> value1 == value2
True
>>> value1 is value2
False

Quando usar qual?

Geralmente isé uma comparação muito mais rápida. É por isso que o CPython armazena em cache (ou talvez reutilize seria o melhor termo) certos objetos como números inteiros pequenos, algumas seqüências de caracteres etc. Mas isso deve ser tratado como um detalhe de implementação que pode (mesmo que improvável) mudar a qualquer momento sem aviso.

Você is deve usar se você:

  • deseja verificar se dois objetos são realmente o mesmo objeto (não apenas o mesmo "valor"). Um exemplo pode ser se você usar um objeto singleton como constante.
  • deseja comparar um valor a uma constante Python . As constantes em Python são:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • classes (por exemplo int is intou int is float)
    • pode haver constantes adicionais nos módulos internos ou nos módulos de terceiros. Por exemplo, np.ma.maskeddo módulo NumPy)

Em qualquer outro caso, você deve usar== para verificar a igualdade.

Posso personalizar o comportamento?

Há um aspecto ==que ainda não foi mencionado nas outras respostas: faz parte do Pythons "Data model" . Isso significa que seu comportamento pode ser personalizado usando o __eq__método Por exemplo:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

Este é apenas um exemplo artificial para ilustrar que o método é realmente chamado:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

Observe que por padrão (se nenhuma outra implementação de __eq__pode ser encontrada na classe ou nas superclasses) __eq__usa is:

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

Portanto, é realmente importante implementar __eq__se você deseja "mais" do que apenas comparação de referência para classes personalizadas!

Por outro lado, você não pode personalizar os ischeques. Ele sempre será comparado apenas se você tiver a mesma referência.

Essas comparações sempre retornam um valor booleano?

Como __eq__pode ser reimplementado ou substituído, não se limita a retornar Trueou False. Ele poderia retornar nada (mas na maioria dos casos ele deve retornar um booleano!).

Por exemplo, com matrizes NumPy ==, retornará uma matriz:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

Mas os ischeques sempre retornam Trueou False!


1 Como Aaron Hall mencionou nos comentários:

Geralmente, você não deve fazer nenhuma verificação is Trueou is Falseporque normalmente as "verificações" são usadas em um contexto que converte implicitamente a condição em um booleano (por exemplo, em uma ifinstrução). Portanto, fazer a is Truecomparação e a conversão booleana implícita está fazendo mais trabalho do que apenas a conversão booleana - e você se limita a booleanos (o que não é considerado pitônico).

Como o PEP8 menciona:

Não compare valores booleanos com Trueou Falseusando ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:
MSeifert
fonte
2
Vou ter que discordar da sua afirmação para comparar "constantes" com is- nomes que apontam para booleanos devem ser verificados com um contexto booleano - como if __debug__:ou if not __debug__:. Você nunca deve fazer if __debug__ is True:ou if __debug__ == True:- além disso, uma constante é apenas um valor semântico constante, não um singleton, portanto, verificar isnesse caso não é semanticamente correto. Desafio você a encontrar uma fonte para apoiar suas afirmações - não acho que você encontrará uma.
Aaron Hall
@AaronHall O que faz você pensar que as constantes não são singletons? Nota que apenas None, True, Falsee __debug__é o que você chamaria de "valor semântico constante", porque eles não podem ser realocados. Mas todos eles são singletons.
precisa saber é o seguinte
Leia PEP 8 - Ctrl-F e procure a palavra "pior". - Se você não está testando, você usaria self.assertTrue
Aaron Hall
@AaronHall Em algumas circunstâncias, você realmente precisa da verificação is Trueou da if Falseverificação (mas sim, essas são muito raras - mas se você as fizer, poderá usá-las is). É por isso que, mesmo CPython usa-los às vezes (por exemplo, aqui ou aqui )
MSeifert
19

Eles são completamente diferentes . isverifica a identidade do objeto, enquanto ==verifica a igualdade (uma noção que depende dos tipos dos dois operandos).

É apenas uma coincidência de sorte que " is" parece funcionar corretamente com números inteiros pequenos (por exemplo, 5 == 4 + 1). Isso ocorre porque o CPython otimiza o armazenamento de números inteiros no intervalo (-5 a 256), tornando-os singletons . Esse comportamento é totalmente dependente da implementação e não é garantido que seja preservado em todos os tipos de operações transformadoras menores.

Por exemplo, o Python 3.5 também cria singletons de cadeias curtas, mas cortá-las interrompe esse comportamento:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False
Dan Lenski
fonte
10

https://docs.python.org/library/stdtypes.html#comparisons

istestes para testes de identidade ==para igualdade

Cada valor inteiro (pequeno) é mapeado para um único valor, portanto, cada 3 é idêntico e igual. Este é um detalhe de implementação, embora não faça parte das especificações de idioma

mmaibaum
fonte
6

Sua resposta está correta. O isoperador compara a identidade de dois objetos. O ==operador compara os valores de dois objetos.

A identidade de um objeto nunca muda depois de criada; você pode pensar nele como o endereço do objeto na memória.

Você pode controlar o comportamento de comparação dos valores do objeto, definindo um __cmp__método ou um método de comparação rico como __eq__.

Dave Webb
fonte
3

Em poucas palavras, isverifica se duas referências apontam para o mesmo objeto ou não. ==verifica se dois objetos têm o mesmo valor ou não.

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 
suvojit_007
fonte
2

Como John Feminella disse, na maioria das vezes você usará == e! = Porque seu objetivo é comparar valores. Gostaria apenas de categorizar o que você faria o resto do tempo:

Há uma e apenas uma instância de NoneType, ou seja, None é um singleton. Consequentemente foo == Nonee foo is Nonesignifica o mesmo. No entanto, o isteste é mais rápido e a convenção Pythonic deve ser usada foo is None.

Se você está fazendo alguma introspecção ou mexendo com a coleta de lixo ou verificando se o seu dispositivo interno de cadeia de caracteres customizado está funcionando ou algo parecido, provavelmente você tem um caso de uso para foois bar.

True e False também são (agora) singletons, mas não há nenhum caso de uso para foo == Truee nenhum caso de uso para foo is True.

John Machin
fonte
2

A maioria deles já respondeu ao ponto. Apenas como uma observação adicional (baseada no meu entendimento e experiência, mas não de uma fonte documentada), a declaração

== se os objetos referidos pelas variáveis ​​forem iguais

das respostas acima devem ser lidas como

== se os objetos referidos pelas variáveis ​​forem iguais e objetos pertencentes ao mesmo tipo / classe

. Cheguei a esta conclusão com base no teste abaixo:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

Aqui, o conteúdo da lista e da tupla são iguais, mas o tipo / classe é diferente.

Sandeep
fonte
2

Diferença de Python entre is e igual (==)

O operador is pode parecer o mesmo que o operador de igualdade, mas não é o mesmo.

O é verifica se ambas as variáveis ​​apontam para o mesmo objeto, enquanto o sinal == verifica se os valores para as duas variáveis ​​são iguais.

Portanto, se o operador is retornar True, a igualdade é definitivamente True, mas o oposto pode ou não ser True.

Aqui está um exemplo para demonstrar a semelhança e a diferença.

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.
Projesh Bhoumik
fonte
1
Use apenas aspas de bloco para o texto que você citou de outra fonte; nesse momento, você deve incluir a atribuição (consulte stackoverflow.com/help/referencing ). Se este for o seu próprio texto, remova as aspas.
Martijn Pieters
0

Como as outras pessoas neste post respondem à pergunta em detalhes, eu enfatizaria principalmente a comparação entre ise == para strings que podem dar resultados diferentes e eu recomendaria aos programadores que os usassem com cuidado.

Para comparação de cadeias, certifique-se de usar em ==vez de is:

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

Fora:

str is hello
str == hello

Mas no exemplo abaixo ==e isobterá resultados diferentes:

str = 'hello sam'
    if (str is 'hello sam'):
        print ('str is hello sam')
    if (str == 'hello sam'):
        print ('str == hello sam')

Fora:

str == hello sam

Conclusão:

Use com iscuidado para comparar entre strings

imanzabet
fonte
por que "é"" trabalho como esse para cordas com espaços?
Akash Gupta
De acordo com as respostas anteriores: Parece que o python executa o cache em números inteiros e strings pequenos, o que significa que utiliza a mesma referência de objeto para ocorrências de string 'hello' neste snapshot de código, enquanto não executou o cache para 'hello sam' como está relativamente maior que 'hello' (ou seja, ele gerencia referências diferentes da string 'hello sam' e é por isso que o operador 'is' retorna falso no exemplo posterior). Corrija-me se estiver errado
Rida Shamasneh