Pourquoi «pas (vrai) dans [faux, vrai]» renvoie faux?

483

Si je fais ça:

>>> False in [False, True]
True

Cela revient True. Tout simplement parce que Falsec'est dans la liste.

Mais si je le fais:

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

Cela revient False. Considérant que not(True)est égal à False:

>>> not(True)
False

Pourquoi?

Texom512
la source
2
vos parenthèses not(True) in [False, True]
prêtent

Réponses:

730

Priorité des opérateurs 2.x , 3.x . La priorité de notest inférieure à celle de in. C'est donc équivalent à:

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

Voici ce que tu veux:

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

Comme le souligne @Ben: il est recommandé de ne jamais écrire not(True), préférez not True. Le premier le fait ressembler à un appel de fonction, tandis que notc'est un opérateur, pas une fonction.

Yu Hao
la source
279
@ Texom512: Je recommanderais également de ne jamais écrire not(True); préférez not True. Le premier le fait ressembler à un appel de fonction, d'où vient votre confusion; si notc'était une fonction, not(True) in ...cela ne pouvait pas l'être not ((True) in ...). Vous devez savoir que c'est un opérateur (ou vous vous retrouvez dans des situations comme celle-ci), vous devez donc l'écrire comme un opérateur, pas le déguiser en fonction.
Ben
7
De plus, si vous allez utiliser l'espacement pour indiquer la priorité au profit du lecteur, assurez-vous d'abord d'avoir raison. C'est probablement OK d'écrire a + b*c + d, c'est très mauvais d'écrire a+b * c+d. Il en not(True)va de même pour cette mesure aussi.
Steve Jessop
32
En fait, n'écrivez jamaisnot True . Écrivez à la Falseplace.
Darkhogg
10
Vraisemblablement dans la vraie vie, vous n'écririez pas not True, vous écririez quelque chose comme not myfunc(x,y,z)myfuncest une fonction qui retourne Trueou False.
Nate CK
3
@ BenC.R.Leggiero C'est ce que j'ai fait dans la réponse originale , et d'autres l'ont corrigée. La version actuelle est assez claire pour moi, je ne pense pas que ce soit difficile à comprendre sans les parenthèses redondantes, puisque le problème clé a été souligné, comprendre le reste est la compétence de base d'un programmeur.
Yu Hao
76

not x in y est évalué comme x not in y

Vous pouvez voir exactement ce qui se passe en démontant le code. Le premier cas fonctionne comme prévu:

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

Le deuxième cas, évalué True not in [False, True], qui est Falseclairement:

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

Ce que vous vouliez plutôt exprimer était (not(True)) in [False, True], ce qui était prévu True, et vous pouvez voir pourquoi:

>>> 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        
Roshan Mathews
la source
13
Il y a toujours un gars avec dismais c'est une réponse très précieuse car elle montre que c'est réellement not inutilisé
jamylak
21
Bytecode est un détail d'implémentation de l'interpréteur CPython. Il s'agit d'une réponse CPython à une question Python, en fait, il peut être mieux répondu directement à partir de la référence du langage.
wim
5
@wim Je dirais que l'implémentation du bytecode n'est pas aussi importante que le démontage réel. Les autres implémentations sont garanties de générer quelque chose de fonctionnellement identique, donc la compréhension d'un désassemblage offre suffisamment d'informations pour comprendre le «pourquoi» et non le «comment» de bas niveau.
Alex Pana
36

Priorité de l'opérateur. inse lie plus étroitement que not, donc votre expression est équivalente à not((True) in [False, True]).

mooiamaduck
la source
33

Tout dépend de la priorité des opérateurs ( inest plus fort que not). Mais il peut être facilement corrigé en ajoutant des parenthèses au bon endroit:

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

l'écriture:

not(True) in [False, True]

est le même que:

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

qui regarde si Trueest dans la liste et retourne le "non" du résultat.

alfasin
la source
14

Il évalue en tant que not True in [False, True], qui renvoie Falsecar Trueest en[False, True]

Si tu essayes

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

Vous obtenez le résultat attendu.

user3636636
la source
13

Parallèlement aux autres réponses qui mentionnent la priorité de notest inférieure à in, votre déclaration équivaut en fait à:

not (True in [False, True])

Mais notez que si vous ne séparez pas votre condition des autres, python utilisera 2 rôles ( precedenceou chaining) afin de séparer cela, et dans ce cas, python a utilisé la priorité. Notez également que si vous souhaitez séparer une condition, vous devez mettre toutes les conditions entre parenthèses, pas seulement l'objet ou la valeur:

(not True) in [False, True]

Mais comme mentionné, il y a une autre modification par python sur les opérateurs qui enchaîne :

Basé sur la documentation de python :

Notez que les comparaisons, les tests d'appartenance et les tests d'identité ont tous la même priorité et ont une fonction de chaînage de gauche à droite comme décrit dans la section Comparaisons.

Par exemple, le résultat de l'instruction suivante est False:

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

Parce que python enchaînera les instructions comme suit:

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

Ce qui est exactement False and Truece qui estFalse .

Vous pouvez supposer que l'objet central sera partagé entre 2 opérations et d'autres objets (False dans ce cas).

Et notez que c'est également vrai pour toutes les comparaisons, y compris les tests d'appartenance et les opérations de tests d'identité qui sont des opérandes suivants:

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

Exemple :

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

Un autre exemple célèbre est la plage de nombres:

7<x<20

ce qui est égal à:

7<x and x<20   
Kasramvd
la source
6

Voyons cela comme une opération de vérification du confinement d'une collection: [False, True] c'est une liste contenant quelques éléments.

L'expression True in [False, True]revient True, commeTrue un élément contenu dans la liste.

Par conséquent, not True in [False, True]donne "l'opposé booléen",not résultat de l'expression ci-dessus (sans aucune parenthèse pour préserver la priorité, comme ina une priorité plus grande que l' notopérateur). Par conséquent, not Truerésultera False.

D'un autre côté (not True) in [False, True],, est égal à False in [False, True], qui est True( Falseest contenu dans la liste).

Nick Louloudakis
la source
6

Pour clarifier certaines des autres réponses, l'ajout de parenthèses après un opérateur unaire ne change pas sa priorité. not(True)ne fait pas notlier plus étroitement à True. C'est juste un ensemble de parenthèses redondantes True. C'est un peu comme (True) in [True, False]. Les parenthèses ne font rien. Si vous voulez que la liaison soit plus serrée, vous devez mettre les parenthèses autour de l'expression entière, ce qui signifie à la fois l'opérateur et l'opérande, c'est-à-dire,(not True) in [True, False] .

Pour voir cela d'une autre manière, considérez

>>> -2**2
-4

** se lie plus étroitement que - , c'est pourquoi vous obtenez le négatif de deux carrés, pas le carré de deux négatifs (qui serait positif de quatre).

Et si vous vouliez le carré de deux négatifs? De toute évidence, vous ajouteriez des parenthèses:

>>> (-2)**2
4

Cependant, il n'est pas raisonnable de s'attendre à ce que 4

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

parce que -(2)c'est la même chose que -2. Les parenthèses ne font absolument rien. not(True)est exactement le même.

asmeurer
la source