9

One of the answers to this question is

print len(s)>5 and 'y' or 'n'
print(len(s)>5 and 'y' or 'n') #python3

if the length of s > 5, then 'y' is printed otherwise 'n' is. Please explain how/why this works. Thanks.

I understand that this is not a recommended approach but I'd like to understand why it works.

Community
  • 1
  • 1
Disnami
  • 2,903
  • 2
  • 17
  • 15

2 Answers2

15

This is an old-fashioned hack. The new way is:

print 'y' if len(s) > 5 else 'n'

The reason it works is because "A and B" will evaluate A, and if it is true, will evaluate to B. But if A is false, it doesn't need to evaluate B. Similarly, "C or D" will evaluate C, and if it is false, will continue on to evaluate as D.

So "A and B or C" is the same as "(A and B) or C". If A is true, it will evaluate B. If A is false, then "(A and B)" is false, so it will evaluate C.

As Voo points out in the comments, the value of A need not be True or False, but any expression, and will be interpreted as a boolean by Python's rules (0, None, and empty containers are false, everything else is true).

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 2
    lol - my 0-point answer gets an own question - and im to late to explain it! ;-) but nice eplanation ;-) – Don Question Jul 15 '12 at 13:34
  • 1
    Might be worth for completeness sake the other "hack" before the `if... else` syntax, which use to be `print {False: 'n', True: 'y'}(len(s) > 5)`(or even just `{0:'n',1:'y'}`) – Jon Clements Jul 15 '12 at 13:35
  • 2
    Meh, there is no "completeness" of pointless hacks. What about `'ny'[len(s) > 5]` ? The ways to abuse the language are endless. – Ned Batchelder Jul 15 '12 at 13:40
  • 1
    The important thing here is that the result of `A and B` is `B` if both A and B evaluate to true and not just `True`. That's not necessarily obvious. – Voo Jul 15 '12 at 13:40
  • 2
    @Voo: actually, "A and B" will evaluate to B if A is a true-ish value, regardless of the value of B. Try "print 1 and 0" – Ned Batchelder Jul 15 '12 at 13:43
  • @Ned Never noticed that, but makes sense. For me the surprising thing when learning was that `A and B` not necessarily returns True/False (or 1/0 back then) but instead an actual value. It's actually quite the nice design imo (although not obvious to newcomers) and I actually still prefer `foo = expensive_func() or default_val` vs. the two liner with ternary if. – Voo Jul 15 '12 at 13:52
  • 1
    @Voo: I use the `x = maybe_this or that` all the time, it's a fine construct. It's the `A and B or C` construct that is a silly hack. – Ned Batchelder Jul 15 '12 at 13:56
0

-- Logical Operators have a precedence from left to right.

-- OR operator does not check the second condition if first is True.

So your code first checks if

 len(s)>5 and 'y'

And this return True, it does not check the second condition of OR thus printing it. Only if this becomes false the second OR condition is checked. This prints 'n'.

For example:

print('a' or 'b')
#Output: a

print(False or 'b')
#Output : b

Thus the OR operator does not check the second condition if first is True.

Rachel Cynthia
  • 126
  • 1
  • 7