2

How is it that, in Python 2.7, the following

True == 'w' in 'what!?'

behaves differently than both

(True == 'w') in 'what!?'

and

True == ('w' in 'what!?')

?

>>> True == 'w' in 'what!?'
False

>>> (True == 'w') in 'what!?'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'in <string>' requires string as left operand, not bool

>>> True == ('w' in 'what!?')
True
NPE
  • 486,780
  • 108
  • 951
  • 1,012

2 Answers2

6

In Python, comparisons can be chained together:

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

So your code is actually equivalent to

>>> (True == 'w') and ('w' in 'what!?')
False
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • Oh wow, `in` is subject to chaining?! Who'd have thought? (+1) – NPE Jan 21 '15 at 15:46
  • Yeah, it's a little surprising because it doesn't look like most other comparison operators, which are predominantly not expressed using letters. But `in` and `is` are full-fledged `comp_operator`s, just like "<" and ">" and "==", etc :-) – Kevin Jan 21 '15 at 15:51
  • 1
    I would have guessed about `is`, but `in` is... unexpected. :) – NPE Jan 21 '15 at 15:56
2

Let's take a look:

>>> import ast
>>> ast.dump(ast.parse("""True == 'w' in 'what!?'""", mode='eval'))
"Expression(body=Compare(left=Name(id='True', ctx=Load()), ops=[Eq(), In()],
comparators=[Str(s='w'), Str(s='what!?')]))"

This is a chained comparison:

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once [...]

ecatmur
  • 152,476
  • 27
  • 293
  • 366