In Python we can do this:
if True or blah:
print(\"it\'s ok\") # will be executed
if blah or True: # will raise a NameError
print(\"it\'s not ok\")
This is called short-circuiting and is a feature of the language:
http://docs.python.org/2/tutorial/datastructures.html#more-on-conditions
The Boolean operators
and
andor
are so-called short-circuit operators: their arguments are evaluated from left to right, and evaluation stops as soon as the outcome is determined. For example, if A and C are true but B is false, A and B and C does not evaluate the expression C. When used as a general value and not as a Boolean, the return value of a short-circuit operator is the last evaluated argument.
With the or
operator, values are evaluated from left to right. After one value evaluates to True
, the entire statement evaluates to True
(so no more values are evaluated).
It's the way the operators logical operators, specifically or
in python work: short circuit evaluation.
To better explain it, consider the following:
if True or False:
print('True') # never reaches the evaluation of False, because it sees True first.
if False or True:
print('True') # print's True, but it reaches the evaluation of True after False has been evaluated.
For more information see the following:
The or
and and
short circuit, see the Boolean operations documentation:
The expression
x and y
first evaluatesx
; ifx
is false, its value is returned; otherwise,y
is evaluated and the resulting value is returned.The expression
x or y
first evaluatesx
; ifx
is true, its value is returned; otherwise,y
is evaluated and the resulting value is returned.
Note how, for and
, y
is only evaluated if x
evaluates to a True value. Inversely, for or
, y
is only evaluated if x
evaluated to a False value.
For the first expression True or blah
, this means that blah
is never evaluated, since the first part is already True
.
Furthermore, your custom Blah
class is considered True:
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false:
False
,None
, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true. (See the __nonzero__() special method for a way to change this.)
Since your class does not implement a __nonzero__()
method (nor a __len__
method), it is considered True
as far as boolean expressions are concerned.
In the expression blah or blah.notexist
, blah
is thus true, and blah.notexist
is never evaluated.
This feature is used quite regularly and effectively by experienced developers, most often to specify defaults:
some_setting = user_supplied_value or 'default literal'
object_test = is_it_defined and is_it_defined.some_attribute
Do be wary of chaining these and use a conditional expression instead where applicable.