0

Recently I came across this code snippet in python:

a = 'holy'
b = 'grail'
c = None
d = a or b or c

print(d) #prints holy

I thought that it would print True. Because bool(a) = True, bool(b) = True, and bool(c) = False, I thought this would simplify to (True or True) or False which is True. Yet, d is simply assigned to a. Do I have a fundamental misunderstanding of how python is working?

Can somebody explain exactly what's going on? Are the or's just superfluous?

Alec
  • 8,529
  • 8
  • 37
  • 63

2 Answers2

1

An or chain returns the first truthy value or the last in the chain if all preceding values are falsey.

So, as the first name a contains a truthy value (empty strings are falsey BTW), the or chain returns that.

Try with a = b = '' and you'll find a or b or c to be returning None (value of c, even it is falsey).

heemayl
  • 39,294
  • 7
  • 70
  • 76
  • This is odd behavior! I'll accept when it lets me. – Alec Mar 23 '19 at 15:45
  • @alec935 Not really. Think of the statement as `d could be equal to a, or it could be equal to b, or it could be equal to c`. – miike3459 Mar 23 '19 at 15:46
  • That makes much more intuitive sense. I'd add it to the answer – Alec Mar 23 '19 at 15:48
  • 1
    @alec935 Just as an addendum, you might also find the use of `and` interesting, as it will also return one of the values of the comparison, instead of True/False values. `d = a and b and c` actually returns `c` (which is `None` in this case). – Luca Bezerra Mar 23 '19 at 15:48
  • Does it return the first Falsey value? – Alec Mar 23 '19 at 15:49
  • @alec935 Yes, it does, good observation! – Luca Bezerra Mar 23 '19 at 15:50
  • @LucaBezerra `and` would return `c` even it were *truthy* (as its the last value). Just remember, `and` will return the first *falsey* value (as opposite to `or`) otherwise the last one (like `or`). – heemayl Mar 23 '19 at 15:51
  • Using XOR seems to return the middle value. a = 0; b = 1; c = 0; d = a ^ b ^ c; print(d) #--> 1 – Alec Mar 23 '19 at 15:53
  • @heemayl Yes, I didn't mean to say it would return `c` just because it was _falsey_ :) – Luca Bezerra Mar 23 '19 at 15:55
0

See @heemayl's answer for an explanation. In order to produce what you want, you could use any, which returns True if any value of the iterable is truthy.

a = 'holy'
b = 'grail'
c = None
d = any([a, b, c])

print(d) # Now prints True
miike3459
  • 1,431
  • 2
  • 16
  • 32