4.2. Operators that return Boolean results

Using the if-then construction correctly entails knowing how to write lines of code that return Boolean results (True or False). Of course we can always write a program (function) of our own to do this. But in many cases, Python provides some simple ways to execute the tests you want and get Boolean results, or results that can be interpreted as Booleans (see below).

The first thing to know is the operators that always return Booleans. In the examples x and y are any Python object.

  1. x in y: Returns True if Python object x is in container y; otherwise returns False.
  2. x < y, x <= y: Returns True if Python object x is “less than, less than or equal to” by general rules of object comparison. Otherwise, returns False. Usually used to compare objects of the same type, or results can be surprising. Works as expected for numbers, strings (alphabetical order).
  3. x > y, x >= y: Returns True if Python object x is “greater than, greater than or equal to” y. Otherwise, returns False.
  4. x == y: Returns True if Python object x is the equivalent to y (e.g., the same number, or a container with the same contents). Otherwise, returns False.
  5. x != y, x <> y: Synonyms; return True if Python object x is not equivalent to object y. If it is equivalent, returns False.
  6. not x: x is a Boolean or something that can be interpreted as a Boolean. not Reverses the Boolean. not True = False and vice versa. :samp:`not can precede any valid test to reverse the value.

4.3. How Boolean tests work

Our previous example of the if-then construction in Python left some details out:

if word in vocabulary:
   results.add(word)

The definition we gave of the if-then construction was that the indented block of code was run if the result of the test was True. The truth is actually a little more complicated — and a little more convenient. A very limited set of Python expression types actually evaluate to True and False (which belong to a special data type all their own called Boolean). For example, if a variable is set to the result of these tests, that variable will have a Boolean value:

>>> X = (2 < 3)
>>> X
True

But Python, like many programming languages allows many different types to occur as the test in an if clause. In most cases, objects of different types behave like True in tests. But each Python type has some special cases that behave like False. The following list summarizes which Python objects behave like False:

  1. None [More on this very special Python object below]
  2. False
  3. zero of any numeric type, for example, 0, 0L, 0.0, 0j.
  4. any empty sequence, for example, '', (), [].
  5. any empty dictionary, for example, {}.
  6. set([])

Thus for example, the following if clause will correctly determine whether the container L is empty:

if L:
  print 'L is not empty`
else:
  print 'L is empty'

4.3.1. The special case of None

Python has a special object with a data type all its own called None. You can think of this a value which stands for no value. The point of having something like this around is that it allows a program to assume an expression has a value, even when it sometimes won’t. For example the variable result might be initialized to None, with the understanding that it will get a meaningful value at some point during the computation, and until that point the name result will still be usable without causing a NameError. It might for example appear in test like the following:

if result:
   return result

This illustrates the property of None introduced above. It behaves like False in a test.

Notes: Prints out as nothing.

4.3.2. Python: expressions versus statements

In principle the expression following an if should be a test and therefore should have Boolean values, either True or False. But as we have just seen, Python objects can in general be interpreted as if they were Booleans, so in fact many different kinds of expressions can quite sensibly follow an if.

But there is one kind of thing which can’t follow if, a simple statement. Here is a list of the Python simple statements that we’ve covered thus far (there are more).

Statement type Example
Assignment X = 3
Pass pass
Del del freq_dict[‘walk’]
Print print result
Return return result
Break break

A simple statement is a Python instruction which doesn’t return anything, by language design. Intuitively this is because each is intended as a program action. Evaluating any one of these to a Python prompt thus returns no result, because there is no value for Python to report:

>>> X = 3
>>> X
3

The first line is a statement, and the Python interpreter returns nothing; the second is an interpreted as a request to return the value of X.

Similarly, trying to set a variable to a Python simple statement is a syntax error (SyntaxError), because there is no value to set the variable to:

>>> dd = dict(a=1)
>>> X = (del dd['a'])
....
X = (del dd['a'])
        ^
SyntaxError: invalid syntax

Finally, writing any one of these after an if is a syntactic error (SyntaxError) . In most cases, it’s pretty hard to imagine anyone making such a mistake. For example:

>>> if pass:
....      ^
SyntaxError: invalid syntax

But one case of using a statement as an if-then test is one of the most common errors made by beginners. See if you can spot that case in the list of statement types above.

The most common error is putting assignments in if tests. Thus, the following innocuous-looking bit of code is a syntax error:

>>> if X=3:
       print 'Eureka!'
if X = 3:
    ^
SyntaxError: invalid syntax

Of course, what was meant was an equality test using ==. Thus:

X == 3

and:

X = 3

mean very different things. The first is a statement which has no value; it simply instructs Python to define the value of the name X to be 3. The second is a test which returns True or False depending on whether the value of the variable X is 3 or not. The first is a syntax error when following if; the second is a valid test.

4.3.3. Conditional expressions

The if-then or conditional construction is closely related to another Python construction called a conditional expression.

Sometimes we want to do a conditional assignment; we want to assign one value to a name under one condition, and another value under another condition. Based on what we’ve covered so far, the job can be done like this:

if condition:
   x = true_value
else:
   x = false_value

But this piece of valid Python code has a small readability issue; it looks like any of the conditional constructions we have discussed in the last two sections and does not make clear that main task of this piece of code is to assign a value to the name x. Accordingly Python provides another more readable construction to do this, allowing the code above to be rewritten as follows:

x = true_value if condition else false_value

The Python idiom on the right of = is an expression (as it has to be, to be legal). As noted above, a Python expression is something that has a value. The value of the expression above depends on the current truth or falsity of condition. Hence, it is a conditional expression. In the documentation which introduces this construction, Guido van Rossum (Python’s inventor and benevolent dictator for life) suggests that it always be used with parentheses, to make the boundaries of the expression clear:

x = (true_value if condition else false_value)

In the typical usage, the else value covers an the unusual case. For example, let doc be some string to be written to a file. In some cases, it’s helpful to end files with a newline character, producing a final empty line, but we don’t want to do that if there’s no content to be written, so we might write:

contents = ((doc + '\n') if doc else '')

Thus, contents has a newline character appended if doc is non-empty. Otherwise, it is the empty string.

To be clear, conditional expressions can be used anywhere an expression can, not just in assignment statements. A very useful case is inside a list comprehension. For example, suppose we want to regularize a sequence of yes-no responses that may be spelled “yes”, “Yes”, “Y”, and so on, but we want to interpret non reponses as no’s:

>>> responses = ['Y', 'Yes', 'No', 'no', '', 'Yep']
>>> responses = [x[0].lower() if x else 'n' for x in responses]
>>> responses
['y', 'y', 'n', 'n', 'n', 'y']