So my boss came up with this (by accident) after a quick search and replace on the code and opening a Pull Request, where tag is always a string:
if "team_" in tag in tag:
To my surprise, that actually works! Not really sure why. I was expecting to parse it from left to right and get an error, like this
>>> ("team_" in "something") in "something"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'in <string>' requires string as left operand, not bool
or even in the worst case, parse it from right to left (which I find it odd, but let's assume it works that way)
>>> "team_" in ("something" in "something")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'bool' is not iterable
but what I got instead was
>>> "team_" in "something" in "something"
False
>>>
>>> "some" in "something" in "something"
True
>>>
can someone explain to me how/why does that work?
CodePudding user response:
It works for the same reason that
1 < x < 10
works. Python allows comparison operators to be chained, so this is equivalent to
1 < x and x < 10
By the same logic
"team_" in tag in tag
is equivalent to
"team_" in tag and tag in tag
When tag
is a string, this is effectively equivalent to just "team_" in tag
, since a string is always in itself. But if tag
is a list or other container it will usually be false because a container doesn't usually contain an instance of itself (it's possible to make recursive references, e.g. mylist.append(mylist)
, and then mylist in mylist
would be true).
CodePudding user response:
You're witnessing chained comparisons (a more classic example being something like a < b < c
)
"some" in "something" in "something"
is the same as
("some" in "something") and ("something" in "something")
so it's valid.
But if you protect one side with parentheses,
("some" in "something") in "something"
aka True in "something"
then you generate a boolean on one side, which explains the error message (the error message is different depending on the side, in the left case it refuses to look for a boolean in a string, and in the right case it refuses to iterate on a boolean)
Yes this natural language stuff is treacherous and can accidentally compile (see a classic issue: How to test multiple variables for equality against a single value?)