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.