3

Recently I have stumbled across an interesting piece of code in Python

condition and 'string1' or 'string2'

It took me some time to figure out its meaning but in the end it is another way to write a ternary expression

'string1' if condition else 'string2'

This made me realise x or y does not return True or False but x if x is True and y otherwise (Python Docs).

However, I don't see the reason why Python was designed that way. I've seen some use cases in checking for None

y = None
x = y or default

but this can be easily and clearer achieved using the following

x = y if y else default

Runtime-wise I also don't see the benefit since, if x is False, the second term in x or y needs to be evaluated at some point.

And in terms of code readability I would expect bool_test = x or y to contain a Boolean value.

So overall, why was Python designed in that way?

  • `y is None` is really only useful for explicitly. Otherwise, `if y:` would suffice. If you want a bool use `bool()` – OneCricketeer Apr 30 '21 at 18:21
  • 2
    This is really a matter of personal (namely, Guido van Rossum's) opinion. – chepner Apr 30 '21 at 18:26
  • There was a time (pre 2.5) when the ternary operator `a = b if c else d` wasn't available. Shorthand like `x = y or z` served as a substitute. It's hard to think of a good justification for that old approach now. – Jamie Deith Apr 30 '21 at 18:26
  • 2
    @JamieDeith There wasn't really a justification for it at the time, either; it was just a mostly-but-not-entirely-correct idiom that people latched on to in the absence of an actual conditional expression. – chepner Apr 30 '21 at 18:32
  • Partly your questin is about boolean expression short-circuiting - e.g. `if x() or y():` if `x()` returns something truthy then the rest of the expression *won’t* be evaluated, i.e. `y()` won’t be called. Similarly for `if x() and y():` if `x()` is falsy then `y()` won’t be evaluated because there’s no point. – DisappointedByUnaccountableMod Apr 30 '21 at 18:35
  • @barny I understand the usefulness of the short-circuiting but I was really wondering why if x() returns something truthy then why would ```x() or y()``` not simply return True? – shiningPanther Apr 30 '21 at 18:39
  • @shiningPanther because the truthiness of the value is just to be used in comparison of the logical operator, not for a value to be returned. Think like this -> `x()` and `y()` both has to FIRST return a value, and then, based on the value, used it in comparison of the `or`. If it is truthy, great, choose it and return it. If they are falsy, then too bad, does not, operation stops. – CozyAzure Apr 30 '21 at 18:43
  • @Tomerikoo that answer explains far more perfectly than my comment – CozyAzure Apr 30 '21 at 18:47
  • @OneCricketeer thanks, I've edited it since I only added it for explicity indeed and don't want the question to be misleading into the truthiness of different Python expressions. – shiningPanther Apr 30 '21 at 18:50
  • @Tomerikoo I understand how the Boolean operators are working but was really wondering what is the benefit of their behaviour. – shiningPanther Apr 30 '21 at 18:53
  • Well that is really a design choice that is better directed at the designers. Here, we can mostly guess... – Tomerikoo Apr 30 '21 at 18:59
  • Related: [Why do 'and' & 'or' return operands in Python?](https://stackoverflow.com/q/22598547/4518341) (this might be a duplicate) – wjandrea Apr 30 '21 at 20:08

1 Answers1

1

Strictly speaking, you are right, when we talk about logical operators - and and or, it should return a boolean - especially if you come from a strictly-typed language.

The thing is, dynamically typed (and often, scripted language) tend to have a wide range of truthiness, aka to evaluate the value of an expression if its TRUE or FALSE. One good example is that in MOST languages, evaluates zero, aka 0 as FALSE, and it is often implied that way.

Just that - in Python - there are whole lots of things that can be evaluated into FALSE, not just an integer of value 0. Empty lists, empty dictionaries, etc, often are implied as falsy aka if you do if [] -> its the same as if len(my_array)==0 which your length of array/lists is 0 and end up giving you a nice Boolean False.

You can take a look at the truthy table of python here

Value Truthiness
True ✅ TRUE
False ❌ FALSE
1 ✅ TRUE
0 ❌ FALSE
-1 ✅ TRUE
"True" ✅ TRUE
"False" ✅ TRUE
"1" ✅ TRUE
"0" ✅ TRUE
"-1" ✅ TRUE
"" ❌ FALSE
None ❌ FALSE
inf ✅ TRUE
-inf ✅ TRUE
[] ❌ FALSE
{} ❌ FALSE
[[]] ✅ TRUE
[0] ✅ TRUE
[1] ✅ TRUE

Readability wise - I think its subjective. x = y or default is definitely shorter than say, you know:

x = y if y is not None else default

because if it is implied that None will always be False, and, unless you have a very strong reason to argue that why None should not be falsy, then why do I bother writing if y is not None? (just evaluate it to False, skip it in the or comparator, and give me default, zoom zoom fast~)

Some people go for succinct code, and they claim it readable. Some like clear, affirmative syntax, like the verbose one, and claim it readable. So I guess that's where you choose your camp :)

wjandrea
  • 28,235
  • 9
  • 60
  • 81
CozyAzure
  • 8,280
  • 7
  • 34
  • 52