Warum gibt "nicht (wahr) in [Falsch, wahr]" Falsch zurück?

483

Wenn ich das mache:

>>> False in [False, True]
True

Das kehrt zurück True . Einfach weil Falseist in der Liste.

Aber wenn ich es mache:

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

Das kehrt zurück False. In der Erwägung not(True), dass False:

>>> not(True)
False

Warum?

Texom512
quelle
2
Ihre Klammern sind verwirrend innot(True) in [False, True]
Grijesh Chauhan

Antworten:

730

Operator Vorrang 2.x , 3.x . Der Vorrang von notist niedriger als der von in. Es ist also gleichbedeutend mit:

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

Das ist, was du willst:

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

Wie @Ben betont: Es wird empfohlen, niemals zu schreiben not(True), lieber not True. Ersteres lässt es wie einen Funktionsaufruf aussehen, während notes sich um einen Operator und nicht um eine Funktion handelt.

Yu Hao
quelle
279
@ Texom512: Ich würde auch empfehlen, niemals zu schreiben not(True); bevorzugen not True. Das erste lässt es wie einen Funktionsaufruf aussehen, von dem Ihre Verwirrung kam; Wenn notes eine Funktion wäre, not(True) in ...könnte es unmöglich sein not ((True) in ...). Sie müssen wissen, dass es sich um einen Operator handelt (oder Sie landen in solchen Situationen), daher sollten Sie ihn wie einen Operator schreiben und nicht als Funktion tarnen.
Ben
7
Wenn Sie den Abstand verwenden, um die Priorität zum Nutzen des Lesers anzuzeigen, stellen Sie zunächst sicher, dass Sie Recht haben. Es ist wahrscheinlich in Ordnung zu schreiben a + b*c + d, es ist sehr schlecht zu schreiben a+b * c+d. Also not(True)ist das auch schlecht.
Steve Jessop
32
Eigentlich nie schreiben not True. Schreiben Sie Falsestattdessen.
Darkhogg
10
Vermutlich im wirklichen Leben würden Sie nicht schreiben werden not True, würden Sie so etwas wie schreiben , not myfunc(x,y,z)wo myfunceine Funktion ist, dass die Renditen Trueoder False.
Nate CK
3
@ BenC.R.Leggiero Das habe ich in der ursprünglichen Antwort getan , und andere haben es korrigiert. Die aktuelle Version ist klar genug für mich, ich denke nicht, dass es ohne die redundanten Klammern schwer zu verstehen ist, da das Hauptproblem aufgezeigt wurde, ist das Verstehen des Restes die grundlegende Fähigkeit eines Programmierers.
Yu Hao
76

not x in y wird bewertet als x not in y

Sie können genau sehen, was passiert, indem Sie den Code zerlegen. Der erste Fall funktioniert wie erwartet:

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

Der zweite Fall bewertet True not in [False, True], was Falseeindeutig ist:

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

Was Sie stattdessen ausdrücken wollten, war (not(True)) in [False, True], was wie erwartet ist True, und Sie können sehen, warum:

>>> 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
quelle
13
Es gibt immer einen Mann mit, disaber dies ist eine sehr wertvolle Antwort, weil es zeigt, dass tatsächlich not inverwendet wird
Jamylak
21
Bytecode ist ein Implementierungsdetail des CPython-Interpreters. Dies ist eine CPython-Antwort auf eine Python-Frage. Tatsächlich kann sie besser direkt aus der Sprachreferenz beantwortet werden.
wim
5
@wim Ich würde argumentieren, dass die Bytecode-Implementierung nicht so wichtig ist wie die eigentliche Demontage. Andere Implementierungen erzeugen garantiert etwas, das funktional identisch ist. Das Verständnis einer Demontage bietet also genügend Einblick, um das "Warum" und nicht das "Wie" auf niedriger Ebene zu verstehen.
Alex Pana
36

Vorrang des Bedieners. inbindet enger als not, so dass Ihr Ausdruck gleichbedeutend ist mit not((True) in [False, True]).

Mooiamaduck
quelle
33

Es geht um die Priorität des Operators ( inist stärker als not). Es kann jedoch leicht korrigiert werden, indem an der richtigen Stelle Klammern eingefügt werden:

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

Schreiben:

not(True) in [False, True]

ist das gleiche wie:

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

Das sieht aus, ob Truees in der Liste ist und gibt das "Nicht" des Ergebnisses zurück.

Alfasin
quelle
14

Es wird als ausgewertet not True in [False, True], was zurückgibt, Falseweil Truein[False, True]

Wenn du es versuchst

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

Sie erhalten das erwartete Ergebnis.

user3636636
quelle
13

Neben den anderen Antworten, bei denen der Vorrang von notniedriger ist als in, entspricht Ihre Aussage tatsächlich:

not (True in [False, True])

Beachten Sie jedoch, dass Python zwei Rollen ( precedenceoder chaining) verwendet, um dies zu trennen , wenn Sie Ihre Bedingung nicht von den anderen trennen. In diesem Fall hat Python Vorrang. Beachten Sie außerdem, dass Sie, wenn Sie eine Bedingung trennen möchten, alle Bedingungen in Klammern setzen müssen, nicht nur das Objekt oder den Wert:

(not True) in [False, True]

Wie bereits erwähnt, gibt es eine weitere Änderung von Python für Operatoren, die verkettet wird :

Basierend auf der Python- Dokumentation :

Beachten Sie, dass Vergleiche, Mitgliedschaftstests und Identitätstests alle dieselbe Priorität haben und eine Verkettungsfunktion von links nach rechts aufweisen, wie im Abschnitt Vergleiche beschrieben.

Das Ergebnis der folgenden Anweisung lautet beispielsweise False:

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

Weil Python die Anweisungen wie folgt verkettet:

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

Welches genau ist False and Truedas?False .

Sie können davon ausgehen, dass das zentrale Objekt von zwei Operationen und anderen Objekten gemeinsam genutzt wird (in diesem Fall False).

Beachten Sie, dass dies auch für alle Vergleiche gilt, einschließlich Mitgliedschaftstests und Identitätsprüfungen, bei denen es sich um folgende Operanden handelt:

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

Beispiel:

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

Ein weiteres berühmtes Beispiel ist der Nummernkreis:

7<x<20

das ist gleich:

7<x and x<20   
Kasramvd
quelle
6

Betrachten wir es als eine Überprüfung der Sammlung von Sammlungen: [False, True]ist eine Liste, die einige Elemente enthält.

Der Ausdruck wird True in [False, True]zurückgegeben True, ebenso Truewie ein in der Liste enthaltenes Element.

Gibt daher not True in [False, True]das "boolesche Gegenteil" als notErgebnis des obigen Ausdrucks an (ohne Klammern, um die Priorität beizubehalten, da es ineine höhere Priorität als der notOperator hat). Daher not Truewird sich ergebenFalse .

Auf der anderen Seite ist (not True) in [False, True], gleich False in [False, True], was ist True( Falseist in der Liste enthalten).

Nick Louloudakis
quelle
6

Um einige der anderen Antworten zu verdeutlichen, ändert das Hinzufügen von Klammern nach einem unären Operator nichts an seiner Priorität. not(True)macht nicht notfester binden an True. Es ist nur ein redundanter Satz von Klammern True. Es ist ähnlich wie (True) in [True, False]. Die Klammern machen nichts. Wenn die Bindung enger sein soll, müssen Sie die Klammern um den gesamten Ausdruck setzen, dh sowohl den Operator als auch den Operanden, dh(not True) in [True, False] .

Um dies anders zu sehen, überlegen Sie

>>> -2**2
-4

**bindet enger als -, weshalb Sie das Negativ von zwei Quadraten erhalten, nicht das Quadrat von negativen zwei (was positiv vier wäre).

Was wäre, wenn Sie das Quadrat der negativen zwei wollten? Natürlich würden Sie Klammern hinzufügen:

>>> (-2)**2
4

Es ist jedoch nicht vernünftig zu erwarten, dass Folgendes gegeben wird 4

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

weil -(2)ist das gleiche wie -2. Die Klammern machen absolut nichts. not(True)ist genau das gleiche.

asmeurer
quelle