Python `se x não for nenhum` ou` se não for x for nenhum`?

747

Eu sempre achei a if not x is Noneversão mais clara, mas o guia de estilo do Google e o PEP-8 usam if x is not None. Existe alguma diferença de desempenho menor (suponho que não) e existe algum caso em que um realmente não se encaixa (tornando o outro um claro vencedor da minha convenção)? *

* Estou me referindo a qualquer singleton, e não apenas None.

... para comparar singletons como Nenhum. O uso é ou não é.

orokusaki
fonte
8
is noté um operador por si só. Like !=. Se você preferir not x is None, também deve preferir not a == bterminar a != b.
Tomasz Gandor
@TomaszGandor Não tenho mais essa opinião not x is None(as respostas aqui me convenceram) - no entanto, vale a pena notar que esse not a == bé o estilo preferido em Python, em comparação com a != b.
orokusaki
4
@orokusaki é not a == brealmente o estilo preferido? Eu nunca vi isso assim e em todos os lugares que olho as pessoas usam !=.
Mike - SMT
2
@orokusaki em Python legibilidade conta isso, é um estilo preferido usar um operador !=em vez de dois operadores not, ==.
Jeyekomon 21/01/19

Respostas:

995

Não há diferença de desempenho, pois eles são compilados no mesmo bytecode:

Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

Estilisticamente, tento evitar not x is y. Embora o compilador sempre o trate como not (x is y), um leitor humano pode entender mal o construto como (not x) is y. Se eu escrevo x is not y, não há ambiguidade.

Daniel Stutzbach
fonte
103
A menos que o mesmo leitor humano pensasse que era x is (not y). Mas eu tendem a concordar com você pelo seu outro raciocínio.
Etaoin
24
adicionalmente, "não é" é menos ambígua neste contexto "se um não é nenhum e b é None:" vs "se não um é Nenhum e b é None:"
Gordon Wrigley
45
o operador deve ser "não"
bean
217

O guia de estilo do Google e do Python é a melhor prática:

if x is not None:
    # Do something about x

O uso not xpode causar resultados indesejados.

Ver abaixo:

>>> x = 1
>>> not x
False
>>> x = [1]
>>> not x
False
>>> x = 0
>>> not x
True
>>> x = [0]         # You don't want to fall in this one.
>>> not x
False

Você pode estar interessado em ver quais literais são avaliados Trueou Falseno Python:


Edite para comentar abaixo:

Acabei de fazer mais alguns testes. not x is Nonenão nega xprimeiro e depois comparado a None. De fato, parece que o isoperador tem uma precedência mais alta quando usado dessa maneira:

>>> x
[0]
>>> not x is None
True
>>> not (x is None)
True
>>> (not x) is None
False

Portanto, not x is Noneé apenas, na minha opinião honesta, melhor evitado.


Mais editar:

Acabei de fazer mais testes e posso confirmar que o comentário do bukzor está correto. (Pelo menos, não consegui provar o contrário.)

Isso significa que if x is not Nonetem o resultado exato como if not x is None. Eu estou corrigido. Obrigado bukzor.

No entanto, minha resposta ainda permanece: use o convencionalif x is not None .:]

Xavier Ho
fonte
131

O código deve ser escrito para ser compreensível para o programador primeiro e o compilador ou intérprete segundo. A construção "não é" se parece mais com o inglês do que "não é".

Mark Ransom
fonte
33

Python if x is not Noneou if not x is None?

TLDR: O compilador de bytecode analisa os dois para x is not None- portanto, para facilitar a leitura, use if x is not None.

Legibilidade

Usamos o Python porque valorizamos coisas como legibilidade humana, usabilidade e correção de vários paradigmas de programação sobre desempenho.

O Python otimiza a legibilidade, especialmente neste contexto.

Analisando e compilando o bytecode

Os not vínculos são mais fracos que is, portanto, não há diferença lógica aqui. Veja a documentação :

Os operadores ise is nottestam a identidade do objeto: x is yé verdadeira se e somente se xey são o mesmo objeto. x is not yproduz o valor inverso da verdade.

O is noté especificamente fornecido na gramática Python como uma melhoria de legibilidade para a linguagem:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

E, portanto, também é um elemento unitário da gramática.

Obviamente, não é analisado da mesma forma:

>>> import ast
>>> ast.dump(ast.parse('x is not None').body[0].value)
"Compare(left=Name(id='x', ctx=Load()), ops=[IsNot()], comparators=[Name(id='None', ctx=Load())])"
>>> ast.dump(ast.parse('not x is None').body[0].value)
"UnaryOp(op=Not(), operand=Compare(left=Name(id='x', ctx=Load()), ops=[Is()], comparators=[Name(id='None', ctx=Load())]))"

Mas o compilador de bytes converterá realmente o not ... ispara is not:

>>> import dis
>>> dis.dis(lambda x, y: x is not y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> dis.dis(lambda x, y: not x is y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

Portanto, para facilitar a leitura e usar o idioma como pretendido, use is not.

Para não usá-lo, não é sábio.

Aaron Hall
fonte
"Os notvínculos são mais fracos que is, portanto, não há diferença lógica aqui" - exceto que o Python não precisa impor identidades lógicas e algébricas para manter (nenhuma razão intrínseca para (1 + 2)*3avaliar o mesmo que 1*3 + 2*3). Aqui, aparentemente, o Python está trapaceando e otimizando UNARY_NOT.
21419 Alexey
30

A resposta é mais simples do que as pessoas estão fazendo.

De qualquer maneira, não há vantagem técnica, e "x não é y" é o que todo mundo usa , o que o torna claramente o vencedor. Não importa que "pareça mais com o inglês" ou não; todo mundo usa, o que significa que todos os usuários do Python - mesmo os usuários chineses, cuja linguagem o Python não se parece - entenderão rapidamente, onde a sintaxe um pouco menos comum precisará de alguns ciclos cerebrais extras para analisar.

Não seja diferente apenas por ser diferente, pelo menos neste campo.

Glenn Maynard
fonte
11

O is notoperador é preferível a negar o resultado ispor razões estilísticas. " if x is not None:" lê como o inglês, mas " if not x is None:" requer entendimento da precedência do operador e não como o inglês.

Se houver uma diferença de desempenho, meu dinheiro estará gasto is not, mas essa certamente não é a motivação para a decisão de preferir essa técnica. Obviamente, seria dependente da implementação. Como isnão é substituível, deve ser fácil otimizar qualquer distinção de qualquer maneira.

Mike Graham
fonte
9

Pessoalmente, eu uso

if not (x is None):

que é entendido imediatamente sem ambiguidade por todo programador, mesmo aqueles que não são especialistas na sintaxe do Python.

MikeTeX
fonte
5
Um argumento justo com o qual concordo, mas acredito que o argumento de seguir o estilo idiomático é mais forte.
Clacke # 7/16
2

if not x is Noneé mais parecido com outras linguagens de programação, mas if x is not Nonedefinitivamente parece mais claro (e é mais gramaticalmente correto em inglês) para mim.

Dito isto, parece que é mais uma coisa de preferência para mim.

Davy8
fonte
0

Eu preferiria a forma mais legível x is not y do que pensaria como escrever a precedência de manipulação de código dos operadores para produzir um código muito mais legível.

stefanogreg
fonte