Existe alguma diferença entre “foo é None” e “foo == None”?

217

Existe alguma diferença entre:

if foo is None: pass

e

if foo == None: pass

A convenção que eu já vi na maioria dos códigos Python (e no código que eu mesmo escrevo) é a primeira, mas recentemente me deparei com um código que usa a segunda. Nenhuma é uma instância (e a única instância, IIRC) de NoneType; portanto, isso não importa, certo? Existem circunstâncias em que isso possa acontecer?

Joe Shaw
fonte

Respostas:

253

issempre retorna Truese comparar a mesma instância do objeto

Considerando que, em ==última análise, é determinado pelo __eq__()método

ie


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False
Brendan
fonte
51
Você pode adicionar que None é um singleton, então "None is None" é sempre True.
e-satis
43
E você pode adicionar que o isoperador não pode ser personalizado (sobrecarregado por uma classe definida pelo usuário).
27510 martineau
@study O método __eq__(self)é um método interno especial que determina como ==é tratado quando usado em um objeto Python. Aqui nós o substituímos para que, quando ==usado em objetos do tipo, Fooele sempre retorne verdadeiro. Não existe um método equivalente para o isoperador e, portanto, o comportamento de isnão pode ser alterado da mesma maneira.
Brendan
É porque a definição da classe foo não possui um construtor, ou seja, a função init ?
estudo
49

Você pode querer ler essa identidade e equivalência do objeto .

A declaração 'is' é usada para a identidade do objeto, verifica se os objetos se referem à mesma instância (mesmo endereço na memória).

E a instrução '==' refere-se à igualdade (mesmo valor).

borrego
fonte
Hmmm, acho que o seu link alterado, a menos que você estava interessado em como chamar funções externas de python
Pat
Eu apenas tentei a=1;b=1;print(a is b) # True. Alguma idéia de por que a is bacaba sendo verdade mesmo que pareçam ser dois objetos diferentes (endereço diferente na memória)?
Johnny Chiu
24

Uma palavra de cautela:

if foo:
  # do something

Não é exatamente o mesmo que:

if x is not None:
  # do something

O primeiro é um teste de valor booleano e pode ser avaliado como falso em diferentes contextos. Existem várias coisas que representam false em um teste de valor booleano, por exemplo, contêineres vazios, valores booleanos. Nenhum também é avaliado como falso nessa situação, mas outras coisas também.

Tendayi Mawushe
fonte
12

(ob1 is ob2) igual a (id(ob1) == id(ob2))

Mykola Kharechko
fonte
6
... mas (ob é ob2) é MUITO mais rápido. Timeit diz que "(a é b)" é 0,0365 usec por loop e "(id (a) == id (b))" é 0,153 usec por loop. 4.2x mais rápido!
AKX 15/10/09
4
a isversão não precisa de chamada de função e nenhuma pesquisa de atributo do interpretador python; o intérprete pode responder imediatamente se ob1 é, de fato, ob2.
U0b34a0f6ae 25/11/2009
17
Não, não tem. {} is {}é falso e id({}) == id({})pode ser (e está no CPython) verdadeiro. Veja stackoverflow.com/questions/3877230
Piotr Dobrogost
12

O motivo foo is Noneé a maneira preferida: você pode estar manipulando um objeto que define o seu próprio __eq__e que define o objeto como sendo igual a Nenhum. Portanto, sempre use foo is Nonese precisar ver se ele está de fato None.

truppo
fonte
8

Não há diferença porque objetos idênticos serão obviamente iguais. No entanto, o PEP 8 afirma claramente que você deve usar is:

Comparações com singletons como None devem sempre ser feitas com é ou não, nunca com os operadores de igualdade.

Thijs van Dien
fonte
7

istestes de identidade, não de igualdade. Para sua declaração foo is none, o Python simplesmente compara o endereço de memória dos objetos. Isso significa que você está fazendo a pergunta "Eu tenho dois nomes para o mesmo objeto?"

==por outro lado, testa a igualdade conforme determinado pelo __eq__()método. Não se importa com identidade.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneé um operador singleton. Então None is Noneé sempre verdade.

In [101]: None is None
Out[101]: True
ChillarAnand
fonte
5

Para Nenhum, não deve haver diferença entre igualdade (==) e identidade (é). O NoneType provavelmente retorna identidade para igualdade. Como None é a única instância que você pode fazer de NoneType (acho que isso é verdade), as duas operações são iguais. No caso de outros tipos, esse nem sempre é o caso. Por exemplo:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Isso imprimiria "Igual", pois as listas têm uma operação de comparação que não é o retorno padrão da identidade.

Stephen Pellicer
fonte
5

@ Jason :

Eu recomendo usar algo mais ao longo das linhas de

if foo:
    #foo isn't None
else:
    #foo is None

Não gosto de usar "if foo:", a menos que foo realmente represente um valor booleano (ou seja, 0 ou 1). Se foo for uma string, um objeto ou outra coisa, "if foo:" pode funcionar, mas me parece um atalho preguiçoso. Se você estiver verificando se x é Nenhum, diga "se x é Nenhum:".

Graeme Perrow
fonte
A verificação de strings / listas vazias com "if var" é a maneira preferida. A conversão booleana está bem definida e é menos código que tem um desempenho melhor. Não há razão para fazer "se len (mylist) == 0", por exemplo.
Truppo 28/05
Errado. Suponha foo = "". Em seguida if foo, retornará falso e o comentário #foo is Noneestá errado.
blokeley
Nota para os que recusam - minha resposta está citando uma resposta que já foi excluída e discordando dela. Se você não gostar do código na minha resposta, precisará votar novamente . :-)
Graeme Perrow
2

Mais alguns detalhes:

  1. A iscláusula realmente verifica se os dois objects estão no mesmo local de memória ou não. ou seja, se ambos apontam para o mesmo local de memória e têm o mesmo id.

  2. Como consequência de 1, isgarante se os dois objects representados lexicamente têm ou não atributos idênticos (atributos-de-atributos ...) ou não

  3. Instanciação de tipos primitivos, como bool, int, string(com algumas excepções), NoneTypetendo um mesmo valor será sempre no mesmo local de memória.

Por exemplo

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

E como NoneTypesó pode ter uma instância na tabela de "pesquisa" do python, a primeira e a segunda são mais um estilo de programação do desenvolvedor que escreveu o código (talvez por consistência), em vez de ter qualquer razão lógica sutil para escolha um sobre o outro.

Dedos Sangrentos
fonte
2
Todo mundo lendo isso: NÃO use some_string is "bar"para comparar SEMPRE. Não há uma única razão aceitável para fazê-lo e ele vai quebrar quando você não espera. O fato de que ele funciona com freqüência é simplesmente porque o CPython sabe que seria estúpido criar dois objetos imutáveis ​​com o mesmo conteúdo. Mas isso pode acontecer mesmo assim.
ThiefMaster 21/10
@ThiefMaster a resposta tem a tendência de ser mal interpretada? Porém, ao lê-lo novamente, não consegui encontrá-lo (com a menção de "algumas exceções"). Sua declaração vale apenas para strings e não int, certo?
Dedos de sangramento
Na verdade, não, mas como você tem esse exemplo em sua resposta, achei que seria uma boa ideia avisar aos usuários que é uma má ideia usá-lo. Talvez adicionar algo como "# CPython específico / não garantida" por trás dessa linha ...
ThiefMaster
1

A conclusão de John Machin que Noneé um singleton é uma conclusão reforçada por esse código.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Uma vez que Noneé um singleton, x == Nonee x is Noneteria o mesmo resultado. No entanto, na minha opinião estética, x == Noneé melhor.

ncmathsadist
fonte
2
Não concordo com a opinião no final desta resposta. Ao comparar com nenhum explicitamente, geralmente se pretende que o objeto em questão seja exatamente o Noneobjeto. Por comparação, raramente se vê Nenhum usado em qualquer outro contexto, exceto para ser semelhante ao fato de Falseoutros valores serem verdadeiros. Nesses casos, é mais idiomático fazer algo comoif x: pass
SingleNegationElimination
0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Aks
fonte