calmthatwombat
calmthatwombat

Reputation: 21

Comparing membership of a list with True operator

Let's say we have

a = [1, 2]

Then in the interpreter,

for e in a: print e in a

prints

True
True

BUT the following code doesn't make sense to me or any of my python-expert friends

for e in a: print e in a == True

prints

False
False

Can someone explain this?

Upvotes: 1

Views: 32

Answers (1)

John Zwinck
John Zwinck

Reputation: 249462

If we boil the confusing expression down, it is:

1 in a == True

This gives False (we might have expected True). So let's use the ast module to inspect it:

>>> import ast
>>> print ast.dump(ast.parse('1 in a == True'))
Module(body=[
  Expr(value=Compare(
      left=Num(n=1),
      ops=[In(), Eq()],
      comparators=[
        Name(id='a', ctx=Load()),
        Name(id='True', ctx=Load())
      ]))
  ])

Compare with a version with added parentheses which works the way you'd probably expect:

>>> print ast.dump(ast.parse('(1 in a) == True'))
Module(body=[
  Expr(value=Compare(
      left=Compare(
        left=Num(n=1),
        ops=[In()],
        comparators=[
          Name(id='a', ctx=Load())
        ]),
      ops=[Eq()],
      comparators=[
        Name(id='True', ctx=Load())
      ]))
  ])

Do you see the difference? The second one is like Eq(In(1, a), True) as we'd expect. But the first is In(1, a) Eq(a, True). What? How do those two things go together? Well, they form a conjunction, like and.

So it ends up that the first expression is equivalent to 1 in a and a == True.

But why?

It's because Python supports "chained conditionals," like this:

1 < 3 < 5

Your example is just collateral damage: apparently not only are conditionals like < chained, but in counts too. This isn't intuitive to me, but that's how it works. You can read more about chaining here: https://docs.python.org/2/reference/expressions.html#not-in

Upvotes: 1

Related Questions