Perché "not (True) in [False, True]" restituisce False?


483

Se lo faccio:

>>> False in [False, True]
True

Questo ritorna True. Semplicemente perché Falseè nell'elenco.

Ma se lo faccio:

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

Questo ritorna False. Considerando che not(True)è uguale a False:

>>> not(True)
False

Perché?



2
le tue parentesi sono confusenot(True) in [False, True]
Grijesh Chauhan,

Risposte:


730

Operatore precedenza 2.x , 3.xe . La precedenza di notè inferiore a quella di in. Quindi è equivalente a:

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

Questo è quello che vuoi:

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

Come sottolinea @Ben: si consiglia di non scrivere mai not(True), preferire not True. Il primo lo fa sembrare una chiamata di funzione, mentre notè un operatore, non una funzione.


279
@ Texom512: consiglierei anche di non scrivere mai not(True); preferisco not True. Il primo lo fa sembrare una chiamata di funzione, da cui proviene la tua confusione; se notfosse una funzione, allora not(True) in ...non potrebbe essere not ((True) in ...). Devi sapere che è un operatore (o finisci in situazioni come questa), quindi dovresti scriverlo come un operatore, non mascherarlo come una funzione.
Ben

7
Inoltre, se hai intenzione di utilizzare la spaziatura per indicare la precedenza a beneficio del lettore, assicurati innanzitutto di avere ragione. Probabilmente è OK scrivere a + b*c + d, è molto brutto scrivere a+b * c+d. Quindi not(True)è male anche per quella misura.
Steve Jessop,

32
In realtà, non scrivere mainot True . Scrivi Falseinvece.
Darkhogg,

10
Presumibilmente nella vita reale non scriveresti not True, scriveresti qualcosa come not myfunc(x,y,z)dove myfuncè una funzione che ritorna Trueo False.
Nate CK,

3
@ BenC.R.Leggiero È quello che ho fatto nella risposta originale , e altri l'hanno corretta. La versione attuale è abbastanza chiara per me, non penso che sia difficile da capire senza le parentesi ridondanti, poiché il problema chiave è stato sottolineato, capire il resto è l'abilità di base di un programmatore.
Yu Hao,

76

not x in y viene valutato come x not in y

Puoi vedere esattamente cosa sta succedendo smontando il codice. Il primo caso funziona come previsto:

>>> 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

Il secondo caso, valuta True not in [False, True], che è Falsechiaramente:

>>> 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        
>>> 

Quello che volevi esprimere invece era (not(True)) in [False, True], come previsto True, e puoi capire perché:

>>> 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
C'è sempre un ragazzo con, disma questa è una risposta molto preziosa perché dimostra che not inviene effettivamente utilizzato
jamylak

21
Bytecode è un dettaglio di implementazione dell'interprete CPython. Questa è una risposta di CPython a una domanda di Python, infatti può essere meglio rispondere direttamente dal riferimento di lingua.
mercoledì

5
@wim Direi che l'implementazione del bytecode non è importante quanto lo smontaggio effettivo. Altre implementazioni sono garantite per generare qualcosa di funzionalmente identico, quindi la comprensione di un disassemblaggio offre una visione sufficiente per capire il "perché" e non il livello basso "come".
Alex Pana,

36

Precedenza dell'operatore. insi lega più strettamente di not, quindi la tua espressione è equivalente a not((True) in [False, True]).


33

Riguarda la precedenza dell'operatore ( inè più forte di not). Ma può essere facilmente corretto aggiungendo le parentesi nel posto giusto:

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

di scrittura:

not(True) in [False, True]

è lo stesso di:

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

che appare se Trueè nell'elenco e restituisce il "non" del risultato.


14

Sta valutando come not True in [False, True], che ritorna Falseperché Trueè dentro[False, True]

Se provi

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

Ottieni il risultato atteso.


13

Oltre alle altre risposte che menzionano la precedenza di notè inferiore a in, in realtà la tua affermazione equivale a:

not (True in [False, True])

Ma nota che se non separi la tua condizione dalle altre, python utilizzerà 2 ruoli ( precedenceo chaining) per separarla, e in questo caso python ha usato la precedenza. Inoltre, tieni presente che se vuoi separare una condizione devi mettere tutta la condizione tra parentesi non solo l'oggetto o il valore:

(not True) in [False, True]

Ma come detto, c'è un'altra modifica di Python sugli operatori che sta concatenando :

Basato sulla documentazione di Python :

Si noti che confronti, test di appartenenza e test di identità hanno tutti la stessa precedenza e dispongono di una funzione di concatenamento da sinistra a destra , come descritto nella sezione Confronti.

Ad esempio, il risultato della seguente dichiarazione è False:

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

Perché python incatenerà le istruzioni come segue:

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

Che è esattamente False and Truequello che è False.

Si può presumere che l'oggetto centrale sarà condiviso tra 2 operazioni e altri oggetti (False in questo caso).

E nota che è vero anche per tutti i confronti, inclusi i test di appartenenza e le operazioni di test di identità che stanno seguendo gli operandi:

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

Esempio :

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

Un altro esempio famoso è l'intervallo di numeri:

7<x<20

che è uguale a:

7<x and x<20   

6

Vediamolo come un'operazione di controllo del contenimento delle raccolte: [False, True]è un elenco contenente alcuni elementi.

L'espressione True in [False, True]ritorna True, come Trueè un elemento contenuto nell'elenco.

Pertanto, not True in [False, True]fornisce il "contrario booleano", notrisultato dell'espressione precedente (senza parentesi per preservare la precedenza, poiché inha una precedenza maggiore rispetto notall'operatore). Pertanto, not Truerisulterà False.

D'altra parte, (not True) in [False, True]è uguale a False in [False, True], che è True( Falseè contenuto nell'elenco).


6

Per chiarire alcune delle altre risposte, l'aggiunta di parentesi dopo un operatore unario non cambia la sua precedenza. not(True)non si notlega più strettamente True. È solo un insieme ridondante di parentesi True. È molto simile a (True) in [True, False]. Le parentesi non fanno nulla. Se vuoi che la rilegatura sia più stretta, devi mettere le parentesi attorno all'intera espressione, ovvero sia l'operatore che l'operando, cioè (not True) in [True, False].

Per vederlo in un altro modo, considera

>>> -2**2
-4

**si lega più strettamente di -, motivo per cui si ottiene il negativo di due quadrati, non il quadrato di due negativi (che sarebbe positivo quattro).

E se volessi il quadrato dei due negativi? Ovviamente, aggiungi le parentesi:

>>> (-2)**2
4

Tuttavia, non è ragionevole aspettarsi quanto segue da dare 4

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

perché -(2)è uguale a -2. Le parentesi non fanno assolutamente nulla. not(True)è esattamente lo stesso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.