Ассоциативность "in" в Python?
Я делаю синтаксический анализатор Python, и это действительно путаешь меня:
>>> 1 in [] in 'a'
False
>>> (1 in []) in 'a'
TypeError: 'in <string>' requires string as left operand, not bool
>>> 1 in ([] in 'a')
TypeError: 'in <string>' requires string as left operand, not list
как именно "in" работает в Python, в отношении ассоциативности и т. д.?
почему ни одно из этих выражений не ведет себя одинаково?
4 ответа:
1 in [] in 'a'
оценивается как(1 in []) and ([] in 'a')
.начиная с первого условия (
1 in []
) составляетFalse
, все состояние оценивается какFalse
;([] in 'a')
на самом деле никогда не оценивается, поэтому ошибка не возникает.вот определения заявления:
In [121]: def func(): .....: return 1 in [] in 'a' .....: In [122]: dis.dis(func) 2 0 LOAD_CONST 1 (1) 3 BUILD_LIST 0 6 DUP_TOP 7 ROT_THREE 8 COMPARE_OP 6 (in) 11 JUMP_IF_FALSE 8 (to 22) #if first comparison is wrong #then jump to 22, 14 POP_TOP 15 LOAD_CONST 2 ('a') 18 COMPARE_OP 6 (in) #this is never executed, so no Error 21 RETURN_VALUE >> 22 ROT_TWO 23 POP_TOP 24 RETURN_VALUE In [150]: def func1(): .....: return (1 in []) in 'a' .....: In [151]: dis.dis(func1) 2 0 LOAD_CONST 1 (1) 3 LOAD_CONST 3 (()) 6 COMPARE_OP 6 (in) # perform 1 in [] 9 LOAD_CONST 2 ('a') # now load 'a' 12 COMPARE_OP 6 (in) # compare result of (1 in []) with 'a' # throws Error coz (False in 'a') is # TypeError 15 RETURN_VALUE In [153]: def func2(): .....: return 1 in ([] in 'a') .....: In [154]: dis.dis(func2) 2 0 LOAD_CONST 1 (1) 3 BUILD_LIST 0 6 LOAD_CONST 2 ('a') 9 COMPARE_OP 6 (in) # perform ([] in 'a'), which is # Incorrect, so it throws TypeError 12 COMPARE_OP 6 (in) # if no Error then # compare 1 with the result of ([] in 'a') 15 RETURN_VALUE
Python делает специальные вещи с цепными сравнениями.
по-разному оцениваются следующие параметры:
x > y > z # in this case, if x > y evaluates to true, then # the value of y is being used to compare, again, # to z (x > y) > z # the parenth form, on the other hand, will first # evaluate x > y. And, compare the evaluated result # with z, which can be "True > z" or "False > z"
в обоих случаях, хотя, если первое сравнение
False
, остальная часть заявления не будет рассматриваться.для вашего конкретного случая,
1 in [] in 'a' # this is false because 1 is not in [] (1 in []) in a # this gives an error because we are # essentially doing this: False in 'a' 1 in ([] in 'a') # this fails because you cannot do # [] in 'a'
кроме того, чтобы продемонстрировать первое правило выше, это утверждения, которые оцениваются как True.
1 in [1,2] in [4,[1,2]] # But "1 in [4,[1,2]]" is False 2 < 4 > 1 # and note "2 < 1" is also not true
приоритет операторов python: http://docs.python.org/reference/expressions.html#summary
сравнения могут быть скованы произвольно, например, x
это означает, что в !
следующие утверждения эквивалентны:
1 in [] in 'a' # <=> middle = [] # False not evaluated result = (1 in middle) and (middle in 'a') (1 in []) in 'a' # <=> lhs = (1 in []) # False result = lhs in 'a' # False in 'a' - TypeError 1 in ([] in 'a') # <=> rhs = ([] in 'a') # TypeError result = 1 in rhs
короткий ответ, так как длинный уже дан несколько раз здесь и в отличных способах, заключается в том, что булево выражение короткое замыкание, это остановило оценку, когда изменение true в false или наоборот не может произойти путем дальнейшей оценки.
(см. http://en.wikipedia.org/wiki/Short-circuit_evaluation)
Это может быть немного коротким (Не каламбур) в качестве ответа, но, как уже упоминалось, все другие объяснения здесь все уже сделано достаточно хорошо, но я подумал, что этот термин заслуживает упоминания.