Learning Python - Mark Lutz [189]
A = [Z, Y][bool(X)]
For example:
>>> ['f', 't'][bool('')]
'f'
>>> ['f', 't'][bool('spam')]
't'
However, this isn’t exactly the same, because Python will not short-circuit—it will always run both Z and Y, regardless of the value of X. Because of such complexities, you’re better off using the simpler and more easily understood if/else expression as of Python 2.5 and later. Again, though, you should use even that sparingly, and only if its parts are all fairly simple; otherwise, you’re better off coding the full if statement form to make changes easier in the future. Your coworkers will be happy you did.
Still, you may see the and/or version in code written prior to 2.5 (and in code written by C programmers who haven’t quite let go of their dark coding pasts...).
* * *
Why You Will Care: Booleans
One common way to use the somewhat unusual behavior of Python Boolean operators is to select from a set of objects with an or. A statement such as this:
X = A or B or C or None
sets X to the first nonempty (that is, true) object among A, B, and C, or to None if all of them are empty. This works because the or operator returns one of its two objects, and it turns out to be a fairly common coding paradigm in Python: to select a nonempty object from among a fixed-size set, simply string them together in an or expression. In simpler form, this is also commonly used to designate a default—the following sets X to A if A is true (or nonempty), and to default otherwise:
X = A or default
It’s also important to understand short-circuit evaluation because expressions on the right of a Boolean operator might call functions that perform substantial or important work, or have side effects that won’t happen if the short-circuit rule takes effect:
if f1() or f2(): ...
Here, if f1 returns a true (or nonempty) value, Python will never run f2. To guarantee that both functions will be run, call them before the or:
tmp1, tmp2 = f1(), f2()
if tmp1 or tmp2: ...
You’ve already seen another application of this behavior in this chapter: because of the way Booleans work, the expression ((A and B) or C) can be used to emulate an if/else statement—almost (see this chapter’s discussion of this form for details).
We met additional Boolean use cases in prior chapters. As we saw in Chapter 9, because all objects are inherently true or false, it’s common and easier in Python to test an object directly (if X:) than to compare it to an empty value (if X != '':). For a string, the two tests are equivalent. As we also saw in Chapter 5, the preset Booleans values True and False are the same as the integers 1 and 0 and are useful for initializing variables (X = False), for loop tests (while True:), and for displaying results at the interactive prompt.
Also watch for the discussion of operator overloading in Part VI: when we define new object types with classes, we can specify their Boolean nature with either the __bool__ or __len__ methods (__bool__ is named __nonzero__ in 2.6). The latter of these is tried if the former is absent and designates false by returning a length of zero—an empty object is considered false.
* * *
* * *
[32] In fact, Python’s X if Y else Z has a slightly different order than C’s Y ? X : Z. This was reportedly done in response to analysis of common use patterns in Python code. According to rumor, this order was also chosen in part to discourage ex-C programmers from overusing it! Remember, simple is better than complex, in Python and elsewhere.
Chapter Summary
In this chapter, we studied the Python if statement. Additionally, because this was our first compound and logical statement, we reviewed Python’s general syntax rules and explored the operation of truth tests in more depth than we were able to previously. Along the way, we also looked at how to code multiway branching in Python and learned about the if/else expression introduced in Python 2.5.
The next chapter