Por que "não (Verdadeiro) em [Falso, Verdadeiro]" retorna Falso?


483

Se eu fizer isso:

>>> False in [False, True]
True

Isso retorna True. Simplesmente porque Falseestá na lista.

Mas se eu fizer:

>>> not(True) in [False, True]
False

Isso retorna False. Considerando que not(True)é igual a False:

>>> not(True)
False

Por quê?



2
os parênteses são confusas emnot(True) in [False, True]
Grijesh Chauhan

Respostas:


730

Operador precedência 2.x , 3.xe . A precedência de noté menor que a de in. Portanto, é equivalente a:

>>> not ((True) in [False, True])
False

Isso é o que você quer:

>>> (not True) in [False, True]
True

Como @Ben aponta: É recomendável nunca escrever not(True), prefira not True. O primeiro faz com que pareça uma chamada de função, enquanto noté um operador, não uma função.


279
@ Texom512: Eu também recomendaria nunca escrever not(True); preferir not True. O primeiro faz com que pareça uma chamada de função, de onde veio sua confusão; se notfosse uma função, not(True) in ...não poderia ser not ((True) in ...). Você precisa saber que é um operador (ou acaba em situações como essa); portanto, você deve escrevê-lo como um operador, não disfarçar isso como uma função.
Ben

7
Além disso, se você usar o espaçamento para indicar precedência em benefício do leitor, primeiro verifique se você está certo. Provavelmente é bom escrever a + b*c + d, é muito ruim escrever a+b * c+d. Então, not(True)é ruim com essa medida também.
21715 Steve Steveop

32
Na verdade, nunca escreva not True. Escreva em seu Falselugar.
21715 Darkhogg

10
Presumivelmente, na vida real, você não escreveria not True, escreveria algo como not myfunc(x,y,z)onde myfuncestá alguma função que retorna Trueou False.
Nate CK

3
@ BenC.R.Leggiero Foi o que fiz na resposta original , e outros a corrigiram. A versão atual é clara o suficiente para mim, não acho difícil entender sem os parênteses redundantes, já que o principal problema foi apontado, entender o resto é a habilidade básica de um programador.
Yu Hao

76

not x in y é avaliado como x not in y

Você pode ver exatamente o que está acontecendo desmontando o código. O primeiro caso funciona como o esperado:

>>> x = lambda: False in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (False)
              3 LOAD_GLOBAL              0 (False)
              6 LOAD_GLOBAL              1 (True)
              9 BUILD_LIST               2
             12 COMPARE_OP               6 (in)
             15 RETURN_VALUE

O segundo caso, avalia para True not in [False, True], que é Falseclaramente:

>>> x = lambda: not(True) in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (True)
              3 LOAD_GLOBAL              1 (False)
              6 LOAD_GLOBAL              0 (True)
              9 BUILD_LIST               2
             12 COMPARE_OP               7 (not in)
             15 RETURN_VALUE        
>>> 

O que você queria expressar era o (not(True)) in [False, True]que, como esperado True, e você pode ver o porquê:

>>> x = lambda: (not(True)) in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (True)
              3 UNARY_NOT           
              4 LOAD_GLOBAL              1 (False)
              7 LOAD_GLOBAL              0 (True)
             10 BUILD_LIST               2
             13 COMPARE_OP               6 (in)
             16 RETURN_VALUE        

13
Há sempre um cara com dismas esta é uma resposta muito valiosa, porque mostra que realmente not iné usado
jamylak

21
Bytecode é um detalhe de implementação do intérprete CPython. Esta é uma resposta do CPython para uma pergunta do Python, na verdade, pode ser melhor respondida diretamente da referência da linguagem.
Wim

5
@wim Eu diria que a implementação do bytecode não é tão importante quanto a desmontagem real. É garantido que outras implementações geram algo funcionalmente idêntico; portanto, entender uma desmontagem oferece insight suficiente para entender o "porquê" e não o "como" de nível inferior.
Alex Pana

36

Operador precedente. invincula com mais força do que not, portanto, sua expressão é equivalente a not((True) in [False, True]).


33

É tudo sobre precedência do operador ( iné mais forte que not). Mas pode ser facilmente corrigido adicionando parênteses no lugar certo:

(not(True)) in [False, True]  # prints true

escrita:

not(True) in [False, True]

é o mesmo que:

not((True) in [False, True])

que parece se Trueestá na lista e retorna o "não" do resultado.


14

Ele está avaliando como not True in [False, True], que retorna Falseporque Trueestá em[False, True]

Se você tentar

>>>(not(True)) in [False, True]
True

Você obtém o resultado esperado.


13

Juntamente com as outras respostas que mencionaram a precedência de, noté menor que in, na verdade, sua declaração é equivalente a:

not (True in [False, True])

Mas observe que, se você não separar sua condição das outras, o python usará duas funções ( precedenceou chaining) para separá-lo e, nesse caso, o python usou precedência. Além disso, observe que, se você quiser separar uma condição, precisará colocar toda a condição entre parênteses, não apenas o objeto ou o valor:

(not True) in [False, True]

Mas, como mencionado, há outra modificação do python nos operadores que está encadeando :

Com base na documentação do python :

Observe que comparações, testes de associação e testes de identidade, todos têm a mesma precedência e um recurso de encadeamento da esquerda para a direita , conforme descrito na seção Comparações.

Por exemplo, o resultado da seguinte instrução é False:

>>> True == False in [False, True]
False

Porque o python encadeará as instruções da seguinte maneira:

(True == False) and (False in [False, True])

O que exatamente é False and Trueisso False.

Você pode assumir que o objeto central será compartilhado entre 2 operações e outros objetos (Falso neste caso).

E observe que também é válido para todas as comparações, incluindo testes de associação e operações de testes de identidade, que são os seguintes operandos:

in, not in, is, is not, <, <=, >, >=, !=, ==

Exemplo:

>>> 1 in [1,2] == True
False

Outro exemplo famoso é o intervalo de números:

7<x<20

que é igual a:

7<x and x<20   

6

Vamos vê-lo como uma operação de verificação de contenção de coleção: [False, True]é uma lista que contém alguns elementos.

A expressão True in [False, True]retorna True, como Trueé um elemento contido na lista.

Portanto, not True in [False, True]fornece o "oposto booleano", notresultado da expressão acima (sem parênteses para preservar a precedência, pois intem maior precedência que o notoperador). Portanto, not Trueresultará False.

Por outro lado (not True) in [False, True],, é igual a False in [False, True], que é True( Falseestá contido na lista).


6

Para esclarecer algumas das outras respostas, adicionar parênteses após um operador unário não altera sua precedência. not(True)não faz notvincular com mais força True. É apenas um conjunto redundante de parênteses True. É quase o mesmo que (True) in [True, False]. Os parênteses não fazem nada. Se você deseja que a ligação seja mais firme, é necessário colocar os parênteses em torno de toda a expressão, significando tanto o operador quanto o operando, ou seja (not True) in [True, False],.

Para ver isso de outra maneira, considere

>>> -2**2
-4

**liga mais firmemente do que -, e é por isso que você obtém o negativo de dois ao quadrado, e não o quadrado do negativo dois (que seria quatro positivo).

E se você quisesse o quadrado dos dois negativos? Obviamente, você adicionaria parênteses:

>>> (-2)**2
4

No entanto, não é razoável esperar que o seguinte dê 4

>>> -(2)**2
-4

porque -(2)é o mesmo que -2. Os parênteses não fazem absolutamente nada. not(True)é exatamente o mesmo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.