Bizarre python functionality with multiple conditions

I had a student I tutored today say that his teacher didn’t like some code he did even though it worked.

He showed me the code and it was something like this:

if bmi  < 25 > 18.5:
    print (“message1”)
if bmi > 25:
    print (“message2”)
if bmi < 18.5:
    print (“message3”)

And it worked! He came up with this on his own (it doesn’t work for bmi exactly equal to 18.5 but that’s a side point).

Is this a known thing? So people often stack multiple conditions in one line like that in Python? Have I been missing out? And how does it parse them? Is it treated as “or” or “and”?

Is a bit silly and the same as if bmi < 25: since 25 is always larger than 18.5.

That said, using if lowerBound < variable < upperBound: is a useful idiom. (substitute <= as needed).

1 Like

Search for “python chaining comparison operators” in your favorite search engine. That first line is meant to be

if 25 > bmi > 18.5:

probaby.

3 Likes

He definitely had bmi first and the < and > later, and we tried all 3 test cases and they all worked. I can see why his teacher told him to do it over again

(looking back, I think it was printing double messages and he only noticed the second ones. I am reconstructing this from memory, I just known the variable came before both inequalities)

Although chaining operators are perfectly legal, I can understand why the teacher didn’t like this example written like that. Consider the alternative:

if bmi > 25:
    print(“message2”)
elif bmi > 18.5:
    print(“message1”)
else:
    print(“message3”)

Now if we want to change the boundary values, we only need to change them in one place. In the original one you need to update each boundary twice and keep them in sync.

1 Like

That’s what I advised him to do in the end. Very clean code you have!

Yeah, the intent is that you can do things like a < expensive_function() < c, without evaluating expensive_function twice. It’s not recommended to use comparisons in multiple directions like this, because it’s hard to understand at a glance—18.5 < bmi < 25 is the clearer way to write it.

2 Likes

A friend once accidentally typed x in y in z as a Python expression, and it took us the longest time to figure out (a) why it was legal and (b) what Python thought it meant.

2 Likes

Hehe, x in y or z is another common mishap or misapprehension.

What does it mean? x in y and y in z?

Yes.

See 6. Expressions — Python 3.12.2 documentation :

Formally, if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c … y opN z is equivalent to a op1 b and b op2 c and … y opN z, except that each expression is evaluated at most once.

4 Likes

See, it now always throws me off that Inform 6 does it that way (x == 5 or 6 or 7) because I’m so used to the C-and-descendants behavior…

2 Likes

And the for x in y or z idiom adds to the confusion in Python.

1 Like

IF-linking point: this clean version works in Ren’Py, the original formulation does not. Firstly, Ren’Py requires “and” or “or” between conditions (so, bmi < 25 and bmi > 18.5). Secondly, “elif” allows the check to be skipped if an earlier check satisfies it, whereas “if” gets treated as a separate check.

bmi > 18.5 excludes 18.5, while => 18.5 includes it. A Ren’Py teacher would probably prefer:

if bmi <= 25 and bmi >= 18.5:
(consequence tabbed)
elif bmi > 25:
(consequences tabbed)
else:
(consequences tabbed)

The latter doesn’t just cover underweight situation, it also catches situations where someone typed in letters, special characters or a negative number. Since the console is always accessible in Ren’Py (barring some truly spectacular means to block it) and it’s always possible to use it to change variables if one knows what the variables are, having an IF that can handle things when someone tries such a trick is a good idea.

1 Like