0

I am still learning the idiosyncrasies of the Python language, and ran into something I find very strange. I could not find another post on SO about this, but please feel free to close as duplicate if I missed it.

The example is as follows:

x = (True, False)
y = (True, True)

print(x and y)  # (True, True)
print(x or y)   # (True, False)

Based on this answer about truthy and falsy values, I would expect the results above to be the same as:

bool(x) and bool(y)  # True
bool(x) or bool(y)   # True

however the value of x and y is not a single boolean, it is a tuple of booleans. Why is that, and how is this tuple computed?

Given that the value is a tuple, the next reasonable thing I would expect is that e.g. x and y would be equal to (x[0] and y[0], x[1] and y[1]), but as you can see that is not the case. The exact same results are obtained when using a list instead of a tuple.

Could a gentle Pythonista please shed some light for me as to what is happening here?

Jonathan H
  • 7,591
  • 5
  • 47
  • 80
  • @Samwise Thanks for your comment; perhaps I am not reading the duplicate question linked correctly, but as I understand it, I would expect the result of `and` and `or` to be a single boolean, not a tuple of booleans. For example `bool(x) and bool(y)` is a single boolean. Why do I get a tuple of booleans above? – Jonathan H Mar 23 '22 at 20:11
  • @TimRoberts That behavior is very interesting! I don't think this is obvious at all, and I don't think this is mentioned in the duplicate answer currently linked. Do you know another question / answer about what you just said? If not, should I reopen the question so you can write an answer about this? – Jonathan H Mar 23 '22 at 20:33
  • 1
    @JonathanH See https://stackoverflow.com/questions/2580136/does-python-support-short-circuiting – eyllanesc Mar 23 '22 at 20:36
  • 1
    @JonathanH I added an extra duplicate – mozway Mar 23 '22 at 20:37
  • @JonathanH The implementation of how "and" and "or" are evaluated is very common in various languages, and the logic is that it is faster than the expected implementation. Let's say you have a function that returns a boolean but it takes a long time and you want to do some action by comparing that value to another using "and" so if the other is false then it is unnecessary to run the time consuming function. – eyllanesc Mar 23 '22 at 20:39
  • @eyllanesc Wonderful, thank you, this is exactly what I was after! This looks somewhat similar to how bash behaves. Could you please add that link to the list of duplicates as well? – Jonathan H Mar 23 '22 at 20:39
  • @eyllanesc Actually, this implementation is not common. This is more than just shortcutting. In C, for example, `&&` always returns 1 or 0. It doesn't actually return the left operand, like Python does. – Tim Roberts Mar 23 '22 at 20:45
  • @TimRoberts In "go" it is already implemented, so other languages are taking advantage of that feature. – eyllanesc Mar 23 '22 at 20:46
  • 1
    [Here](https://docs.python.org/3/library/stdtypes.html#truth-value-testing) is the relevant section in the docs. – juanpa.arrivillaga Mar 23 '22 at 21:26
  • 1
    @JonathanH might be worth moving your answer from the question section into the answer section – Sam Mason Mar 31 '22 at 09:53
  • @SamMason Thanks, I thought the question had been closed as duplicate. Please see my answer below! – Jonathan H Mar 31 '22 at 23:46
  • @JonathanH no idea, maybe your edits prompted it to be reopened? there might be something better to tag it as a dup of, but ah well, you've written it nicely! – Sam Mason Apr 01 '22 at 07:40

1 Answers1

1

Many thanks in particular to @eyllanesc for their comments.

Based on this answer, and on the docs, the answer is called short-circuiting, and the behavior is rather unsual in Python in that the truthiness of the operands is evaluated to determine the return value, but the value of an operand (and not its truthiness) is returned.

In particular, the seemingly problematic examples in the OP are expected behavior, and can be explained with the following equivalences:

  • x and y is equivalent to y if bool(x) else x
  • x or y is equivalent to x if bool(x) else y
Jonathan H
  • 7,591
  • 5
  • 47
  • 80