3.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.
x in y
: ReturnsTrue
if Python objectx
is in containery
; otherwise returnsFalse
.x < y, x <= y
: ReturnsTrue
if Python objectx
is “less than, less than or equal to” by general rules of object comparison. Otherwise, returnsFalse
. Usually used to compare objects of the same type, or results can be surprising. Works as expected for numbers, strings (alphabetical order).x > y, x >= y
: ReturnsTrue
if Python objectx
is “greater than, greater than or equal to”y
. Otherwise, returnsFalse
.x == y
: ReturnsTrue
if Python objectx
is the equivalent toy
(e.g., the same number, or a container with the same contents). Otherwise, returnsFalse
.x != y, x <> y
: Synonyms; returnTrue
if Python objectx
is not equivalent to objecty
. If it is equivalent, returnsFalse
.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.not
can precede any valid test to reverse the value.
3.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
:
None
[More on this very special Python object below]False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example,
'', (), [].
any empty dictionary, for example,
{}
.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')
3.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.
3.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’] |
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.
3.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']