Here's a Python 'gotcha' I spotted in this StackOverflow question the other day. It's not something that's ever bitten me, but I thought it was interesting enough to write a quick post about.

Anyone who's used Python for a good length of time has probably come across the idea of operator chaining. In languages like C, to check that a value was in a certain range, you'd do something like this:

``````if ((low <= x) && (x < upper)){
// Do something here!
}
``````

It's fairly concise, but it gets ugly pretty quickly if there's more than a couple of conditions.

In Python, it's a lot simpler - just use the mathematical style of 'chaining' operators:

``````if low <= x < upper:
# Do something here!
``````

The documentation for operator precedence can be found here. The operators `in`, `not in`, `is`, `is not`, `<`, `<=`, `>`, `>=`, `!=` and `==` all have the same precedence which gives some strange results, like the one referenced in the StackOverflow question above.

Consider the expression `x in y == True`, where `x` is some object such that `x in y` evaluates to `True` and `y` is some object such that `y != True`.

The obvious, wrong answer is that the expression evaluates to `True`. In fact:

``````>>> x in y
True
>>> x in y == True
False
``````

This assumption turns out to be false. The logical next step is that there's an operator precedence issue - but we've just ascertained that `in` and `==` have the same precedence. Instead of correcting it immediately, we can try to reproduce the error more clearly:

``````>>> x in (y == True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'bool' is not iterable
``````

Makes sense - but it raises the question of how exactly the original expression is evaluating to `False`, instead of either evaluating to `True` or raising a `TypeError`.

The answer lies in the chaining demonstrated above: what's really happening is this:

``````(x in y) and (y == True)
``````

Since `y` is presumably some sequence (or custom object with a `__contains__` method), we know it's definitely not equal to `True`.

To get the result we want, of course, we just put the first expression in brackets:

``````(x in y) == True
``````

Although, in practice, it's not worth checking for equality to a boolean - just checking if the result is truthy or falsy will likely be enough:

``````if x in y:
# Do something!
``````

I've never once written - or personally come across, besides that SO question - any code that chains operators of that precedence other than the "limit" operators. It's hard to think of where `x in y in z` would ever come in handy, although I'd concede that `x != y != z` might be a neat way to save a few characters if you're code-golfing (with the spaces removed, of course!).

Edit: I just came across another possibility for where chaining mixed operators could come in handy:

``````if x < f() != y:
# Do something!
``````

We save some screen space by eliminating a variable for the two checks against the function's return value - `f()` is only evaluated once, whereas the following would evaluate it twice:

``````x < f() and f() != y
``````

But really, minimising vertical space shouldn't be of a higher priority than code clarity, and this works just as well:

``````result = f()
if x < result and result != y:
# Do something!
``````