diveintopython.org
Python for experienced programmers

 

2.7. The and-or trick

If you're a C hacker, you are certainly familiar with the bool ? a : b expression, which evaluates to a if bool is true, and b otherwise. Like many programming tricks, this is seductively convenient. You can accomplish the same thing in Python, but you need to understand precisely how it works to avoid a subtle pitfall.

Example 2.17. Introducing the and-or trick

>>> a = "first"
>>> b = "second"
>>> 1 and a or b 1
'first'
>>> 0 and a or b 2
'second'
1 This syntax looks similar to the bool ? a : b expression in C. The first part will be evaluated in a boolean context, and it can be any Python expression. If it evaluates true, the whole expression is the value of a.
2 If the first part evaluates false, the whole expression is the value of b.

However, since this Python expression is simply boolean logic, and not a special construct of the language, there is one very, very, very important difference between this and-or trick in Python and the bool ? a : b syntax in C. If the value of a is false, the expression will not work as you would expect it to. (Can you tell I was bitten by this? More than once?)

Example 2.18. When the and-or trick fails

>>> a = ""
>>> b = "second"
>>> 1 and a or b
'second'

Since a is an empty string, which Python considers false in a boolean context, this expression will “fall through” and return the value of b. If you stop thinking of it as the bool ? a : b syntax and see it as pure boolean logic, this makes perfect sense. 1 is true, a is false, so 1 and a is false. False or b is b.

Important
The and-or trick, bool and a or b, will not work like the C expression bool ? a : b when a is false.

The real trick behind the and-or trick, then, is to make sure that the value of a is never false. One common way of doing this is to turn a into [a] and b into [b], then taking the first element of the returned list, which will be either a or b.

Example 2.19. Using the and-or trick safely

>>> a = ""
>>> b = "second"
>>> (1 and [a] or [b])[0]
''

Since [a] is a non-empty list, it is never false. Even if a is 0 or '' or some other false value, the list [a] is true because it has one element.

By now, this trick may seem like more trouble than it's worth. You could, after all, accomplish the same thing with an if statement, so why go through all this fuss? Well, in many cases, you are choosing between two constant values, so you can use the simpler syntax and not worry, because you know that the a value will always be true. And even if you have to use the more complicated safe form, there are good reasons to do so; there are some cases in Python where if statements are not allowed, as we'll see in the next section.

Note
A conscientous programmer could encapsulate the and-or trick into a function:
def choose(bool, a, b):
    return (bool and [a] or [b])[0]