Почему «не (True) в [False, True]» возвращает False?

483

Если я сделаю это:

>>> False in [False, True]
True

Это возвращается True. Просто потому что Falseесть в списке.

Но если я сделаю:

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

Это возвращается False. Принимая во внимание, not(True)что равно False:

>>> not(True)
False

Почему?

Texom512
источник
1
связанные с stackoverflow.com/questions/31354429/…
Kasramvd
2
Ваши круглые скобки сбивают с толкуnot(True) in [False, True]
Grijesh Chauhan

Ответы:

730

Приоритет операторов 2.x , 3.x . Приоритет notниже, чем у in. Так что это эквивалентно:

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

Это то, что вы хотите:

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

Как отмечает @Ben: рекомендуется никогда не писать not(True), предпочитайте not True. Первый делает его похожим на вызов функции, а notявляется оператором, а не функцией.

Ю Хао
источник
279
@ Texom512: я бы также рекомендовал никогда не писать not(True); предпочитают not True. Первый делает его похожим на вызов функции, откуда и возникла ваша путаница; если бы notбыла функция, то not(True) in ...не могло бы быть not ((True) in ...). Вы должны знать, что это оператор (или вы попадаете в подобные ситуации), поэтому вы должны писать его как оператор, а не маскировать его как функцию.
Бен
7
Кроме того, если вы собираетесь использовать интервалы, чтобы указать приоритет для читателя, сначала убедитесь, что вы правы. Писать наверное нормально, писать a + b*c + dочень плохо a+b * c+d. Так not(True)плохо от этой меры тоже.
Стив Джессоп
32
На самом деле, никогда не пиши not True. Напишите Falseвместо.
Darkhogg
10
Предположительно, в реальной жизни вы бы не писали not True, вы писали бы что-то вроде not myfunc(x,y,z)где myfuncкакая-то функция, которая возвращает Trueили False.
Нэйт К.К.
3
@ BenC.R.Leggiero Это то, что я сделал в первоначальном ответе , и другие исправили это. Текущая версия достаточно ясна для меня, я не думаю, что это трудно понять без лишних скобок, так как была указана ключевая проблема, понимание всего остального - базовый навык программиста.
Ю Хао
76

not x in y оценивается как x not in y

Вы можете точно увидеть, что происходит, разобрав код. Первый случай работает так, как вы ожидаете:

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

Во втором случае оценивается True not in [False, True], чтоFalse явно:

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

Вместо этого вы хотели выразить то (not(True)) in [False, True], что ожидалось True, и вы можете понять, почему:

>>> 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
Всегда есть парень с, disно это очень ценный ответ, потому что он показывает, что на самом деле not inиспользуется
jamylak
21
Байт-код - это деталь реализации интерпретатора CPython. Это ответ CPython на вопрос о Python, на самом деле на него лучше ответить непосредственно из языковой справки.
Вим
5
@wim Я бы сказал, что реализация байт-кода не так важна, как фактическая разборка. Другие реализации гарантированно генерируют что-то функционально идентичное, поэтому понимание одной разборки дает достаточно понимания, чтобы понять «почему», а не низкоуровневое «как».
Алекс Пан
36

Приоритет оператора. inсвязывает более плотно, чем not, поэтому ваше выражение эквивалентно not((True) in [False, True]).

mooiamaduck
источник
33

Это все о приоритете оператора ( inсильнее, чем not). Но это можно легко исправить, добавив скобки в нужном месте:

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

письмо:

not(True) in [False, True]

так же, как:

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

который смотрит, Trueнаходится ли в списке и возвращает «не» результата.

alfasin
источник
14

Он оценивается как not True in [False, True], который возвращает, Falseпотому что Trueнаходится в[False, True]

Если вы пытаетесь

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

Вы получите ожидаемый результат.

user3636636
источник
13

Наряду с другими ответами, в которых упоминается приоритет notниже in, фактически ваше утверждение эквивалентно:

not (True in [False, True])

Но обратите внимание, что если вы не отделяете свое условие от других, python будет использовать 2 роли ( precedenceили chaining), чтобы отделить это, и в этом случае python использовал приоритет. Также обратите внимание, что если вы хотите отделить условие, вам нужно поместить все условие в скобки, а не только объект или значение:

(not True) in [False, True]

Но, как уже упоминалось, есть еще одна модификация python для операторов, которая является цепочкой :

На основании документации по питону :

Обратите внимание, что сравнения, тесты на членство и тесты на идентичность имеют одинаковый приоритет и имеют функцию сцепления слева направо, как описано в разделе «Сравнения».

Например, результат следующего утверждения False:

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

Потому что python будет связывать операторы следующим образом:

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

Что именно False and TrueэтоFalse .

Вы можете предположить, что центральный объект будет разделен между двумя операциями и другими объектами (в данном случае False).

И обратите внимание, что это также верно для всех сравнений, включая тесты членства и тесты идентичности, которые являются следующими операндами:

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

Пример :

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

Другой известный пример - диапазон номеров:

7<x<20

который равен:

7<x and x<20   
Kasramvd
источник
6

Давайте рассмотрим это как операцию проверки содержания коллекции: [False, True] это список, содержащий некоторые элементы.

Выражение True in [False, True]возвращается True, какTrue элемент содержится в списке.

Следовательно, not True in [False, True]дает «булево противоположное», notрезультат вышеприведенного выражения (без скобок для сохранения приоритета, поскольку inимеет больший приоритет, чем notоператор). Поэтому not Trueи приведу False.

С другой стороны, (not True) in [False, True]равно False in [False, True], что есть True(False содержится в списке).

Ник Лулудакис
источник
6

Чтобы уточнить некоторые другие ответы, добавление скобок после унарного оператора не меняет его приоритета. not(True)не делает notсвязывать более плотно True. Это просто избыточный набор круглых скобок True. Это так же, как (True) in [True, False]. Скобки ничего не делают. Если вы хотите, чтобы привязка была более узкой, вы должны поместить круглые скобки вокруг всего выражения, означая как оператор, так и операнд, т.е.(not True) in [True, False] .

Чтобы увидеть это по-другому, рассмотрим

>>> -2**2
-4

** связывает более плотно, чем - , поэтому вы получаете отрицательный квадрат в два, а не квадрат отрицательного два (который был бы положительным четыре).

Что если вы хотите получить квадрат отрицательных двух? Очевидно, вы бы добавили скобки:

>>> (-2)**2
4

Тем не менее, не стоит ожидать, что следующее 4

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

потому -(2)что так же, как -2. Скобки ничего не делают. not(True)точно так же.

asmeurer
источник