Eu já vi vários exemplos de código como este:
if not someobj:
#do something
Mas eu estou querendo saber por que não fazer:
if someobj == None:
#do something
Existe alguma diferença? Um tem uma vantagem sobre o outro?
X != None?
Eu já vi vários exemplos de código como este:
if not someobj:
#do something
Mas eu estou querendo saber por que não fazer:
if someobj == None:
#do something
Existe alguma diferença? Um tem uma vantagem sobre o outro?
X != None?
Respostas:
No primeiro teste, o Python tenta converter o objeto em um boolvalor, caso ainda não o seja. A grosso modo, estamos perguntando o objeto: você é significativo ou não? Isso é feito usando o seguinte algoritmo:
Se o objeto tiver um __nonzero__método especial (assim como os embutidos numéricos inte float), ele chamará esse método. Ele deve retornar um boolvalor que é então usado diretamente ou um intvalor que é considerado Falseigual a zero.
Caso contrário, se o objeto tem um __len__método especial (como fazem recipiente built-ins, list, dict, set, tuple, ...), ele chama esse método, considerando um recipiente Falsese ela estiver vazia (comprimento é zero).
Caso contrário, o objeto será considerado, a Truemenos que None, nesse caso, seja considerado False.
No segundo teste, o objeto é comparado para igualdade com None. Aqui, estamos perguntando ao objeto: "Você é igual a esse outro valor?" Isso é feito usando o seguinte algoritmo:
Se o objeto tiver um __eq__método, ele será chamado e o valor de retorno será convertido em um boolvalor e usado para determinar o resultado de if.
Caso contrário, se o objeto tiver um __cmp__método, ele será chamado. Esta função deve retornar um intindicando a ordem dos dois objetos ( -1se self < other, 0se self == other, +1se self > other).
Caso contrário, o objeto é comparado à identidade (ou seja, é referência ao mesmo objeto, como pode ser testado pelo isoperador).
É possível outro teste usando o isoperador. Nós estaríamos perguntando ao objeto: "Você é esse objeto em particular?"
Geralmente, eu recomendaria usar o primeiro teste com valores não numéricos, usar o teste de igualdade quando desejar comparar objetos da mesma natureza (duas cadeias, dois números, ...) e verificar a identidade apenas quando usando valores sentinela ( Noneou seja, não inicializado para um campo de membro por exemplo, ou ao usar getattros __getitem__métodos ou ).
Para resumir, temos:
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
Na verdade, essas são duas práticas ruins. Era uma vez, considerado OK tratar casualmente Nenhum e Falso como semelhantes. No entanto, desde o Python 2.2, essa não é a melhor política.
Primeiro, quando você faz um if xou if not xtipo de teste, o Python precisa converter implicitamente xem booleano. As regras para a boolfunção descrevem uma série de coisas que são falsas; tudo o resto é verdadeiro. Se o valor de x não era propriamente booleano, essa conversão implícita não é realmente a maneira mais clara de dizer as coisas.
Antes do Python 2.2, não havia função bool, portanto era ainda menos clara.
Segundo, você realmente não deveria testar == None. Você deve usar is Nonee is not None.
Consulte PEP 8, Guia de estilo para código Python .
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
Quantos singletons existem? Cinco: None, True, False, NotImplementede Ellipsis. Já que é improvável que você use NotImplementedou Ellipsisnunca diria if x is True(porque simplesmente if xé muito mais claro), você só testará None.
Porque Nonenão é a única coisa que é considerada falsa.
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False, 0, (), [], {}E ""são todos diferentes None, para que seus dois trechos de código são não equivalente.
Além disso, considere o seguinte:
>>> False == 0
True
>>> False == ()
False
if object:não é uma verificação de igualdade. 0, (), [], None, {}, Etc. são todos diferentes uns dos outros, mas todos eles avaliar a False.
Esta é a "mágica" por trás de expressões de curto-circuito como:
foo = bar and spam or eggs
que é uma abreviação para:
if bar:
foo = spam
else:
foo = eggs
embora você realmente deva escrever:
foo = spam if bar else egg
O PEP 8 - Guia de Estilo para Código Python recomenda o uso é ou não, se você estiver testando o None-ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
Por outro lado, se você estiver testando mais do que Nada, deve usar o operador booleano.
Se você perguntar
if not spam:
print "Sorry. No SPAM."
o método __nonzero__ de spam é chamado. No manual do Python:
__nonzero__ ( self ) Chamado para implementar testes de valor verdade e a operação interna bool (); deve retornar False ou True, ou seus equivalentes inteiros 0 ou 1. Quando esse método não é definido, __len __ () é chamado, se for definido (veja abaixo). Se uma classe não define __len __ () nem __nonzero __ (), todas as suas instâncias são consideradas verdadeiras.
Se você perguntar
if spam == None:
print "Sorry. No SPAM here either."
o método __eq__ de spam é chamado com o argumento Nenhum .
Para obter mais informações sobre as possibilidades de personalização, consulte a documentação do Python em https://docs.python.org/reference/datamodel.html#basic-customization
Essas duas comparações servem a propósitos diferentes. O primeiro verifica o valor booleano de algo, o segundo verifica a identidade com o valor Nenhum.
A resposta é "depende".
Eu uso o primeiro exemplo se considerar 0, "", [] e False (lista não exaustiva) como equivalentes a Nenhum neste contexto.
Pessoalmente, escolhi uma abordagem consistente entre os idiomas: eu faço if (var)(ou equivalente) apenas se var for declarado como booleano (ou definido como tal, em C não temos um tipo específico). Eu prefixo essas variáveis com a b(então seria bVarrealmente) para ter certeza de que não usarei acidentalmente outro tipo aqui.
Eu realmente não gosto de conversão implícita para booleana, menos ainda quando existem inúmeras regras complexas.
Claro, as pessoas vão discordar. Alguns vão além, eu vejo if (bVar == true)no código Java no meu trabalho (redundante demais para o meu gosto!), Outros adoram sintaxe compacta demais, indo while (line = getNextLine())(ambígua demais para mim).