Using logical operators in Python without a condition - python

This seems like a simple question but I was unable to find a precedent. One answer here points it out without explaining why.
Using logical operators without two variables returns not a boolean but one of the variables - the first for OR and the second for AND.
'x' or 'y'
> 'x'
3 and 4
> 4
What's the reason for this behaviour?

The reason is that that is the most efficient way to shortcut evaluation of boolean expressions. With or Python returns the first truthy value that it encounters. It doesn't need to evaluate the rest to discover if the expression is true. Similarly, with and Python returns the first falsy value that it encounters. It doesn't need to evaluate the rest to discover if the expression is false.
If it bothers you that you get a non-boolean back, then wrap a call to bool() around your expression.

Related

Why is the last number returned when putting "and" in python? [duplicate]

First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.

Confused about Operator Precedence in Python

I was playing around with logical expressions in the python interpreter, and I can't seem to figure out what execution procedure python is really using under the hood. I've seen this table (http://www.mathcs.emory.edu/~valerie/courses/fall10/155/resources/op_precedence.html) as describing the operator precedence that python uses.
1)
print("this") or True and 1/0 and print("tester")
when I type that into the python interpreter I get the output of "this" and then zero division error. However, the site I referenced mention that function calls are the second highest precedence, so shouldn't both function calls of print be executed first? I know there's short circuit evaluation, but doesn't that kick in only once you get to the precedence level of the ands, nots, and ors?
2)
True>False or print("hello")
even this outputs only True on the python interpreter. why doesn't it do the function call of print first?
3)
5 is 5 or 1/0
This outputs True. But shouldn't division have higher precedence than "is" and shouldn't this expression return a ZeroDivsionError?
Can someone explain what I'm missing and how to tell in what order python will execute a logical expression?
Can someone explain what I'm missing and how to tell in what order python will execute a logical expression?
Precedence affects which way "shared" operands will be grouped when parsing to a tree. Past that, the specific evaluation model of each sub-expression takes over.
print("this") or True and 1/0 and print("tester")
You get a tree which looks like this (you can get the more verbose but exact version using the ast module, and astpretty to get something readable):
or
print("this")
and
True
and
1/0
print("tester")
Then evaluation takes over (after a compilation to bytecode but that doesn't change the order of operation):
the outer or is evaluated
it evaluates the first print, which returns a falsy value, therefore
it evaluates the first and
it evaluates True which is truthy
therefore it evaluates the second and
which evaluates 1/0 which blows up
True>False or print("hello")
This parses to
or
>
True
False
print("hello")
or evaluates its first operand
(> True False) evaluates to True
or is a short-circuiting operator, it stops as soon as it finds a truthy value and returns that, so it never gets to the print
5 is 5 or 1/0
This parses to
or
is
5
5
/
1
0
or is evaluated
is is evaluated, and returns True
as above, or is a short-circuiting operator and returns the first truthy value, so it returns immediately.
I left out some bits e.g. technically / evaluates both operands then applies its operation, function calls evaluate all their parameters then perform the call itself.
and and or stand out because they perform logic after the evaluation of each operand, not after having evaluated all of them (they're lazy / short-circuiting): and returns the first falsy result it gets, or returns the first truthy result it gets, potentially evaluating only the first of their operands.
Precedence order is used by the parser to construct a parse tree. It does not mean the same as evaluation order.
Taking your 3rd case as an example: 5 is 5 or 1/0. The precedence order is / > is > or.
The parse tree would look something like this (according to the precedence.)
or
/ \
is div
/ \ / \
5 5 1 0
Evaluation (technically, code generation) starts from the top, in this case, the or node, according to another rule provided to the code generator. The output of a code generator for or may look something like this.
t = code(5 is 5)
if t goto L1
L2: code(1/0)
goto L1
L1:
The precedence order was only used initially to create the parse tree. Once the parse tree is constructed, semantic rules (actions? i'm forgetting words) come into play.
The short circuit behavior is built into the or node's semantic rule.
p.s. This answer is not for Python specifically.
Precedence does not affect the order in which python evaluates statements. In 5 is 5 or 1/0, python first checks if 5 is 5 is true, and if it is, it ignores the second statement. In other words python always evaluates the first statement first, regardless of precedence

What does an 'x = y or z' assignment do in Python?

Why do we see Python assignments with or?
For example:
def my_function(arg_1=None, arg_2=0):
determination = arg_1 or arg_2 or 'no arguments given!'
print(determination)
return determination
When called with no arguments, the above function would print and return 'no arguments given!'
Why does Python do this, and how can one best make best use of this functionality?
What the "or" expression does on assignment:
We sometimes see examples of this in Python as a substitute for conditional expression with ternary assignments, (in fact, it helped inspire the language to add conditional statements).
x = a or b
If bool(a) returns False, then x is assigned the value of b
Identical Use-case of Conditional Expressions (i.e. Ternary Assignments)
Here's an example of such a conditional expression that accomplishes the same thing, but with perhaps a bit less mystery.
def my_function(arg_1=None, arg_2=0):
determination = arg_1 if arg_1 else arg_2 if arg_2 else 'no arguments given!'
print(determination)
return determination
Repeating this syntax too much is considered to be bad style, otherwise it's OK for one-liners. The downside is that it is a bit repetitive.
or Expressions
The base case, x or y returns x if bool(x) evaluates True, else it evaluates y, (see the docs for reference). Therefore, a series of or expressions has the effect of returning the first item that evaluates True, or the last item.
For example
'' or [] or 'apple' or () or set(['banana'])
returns 'apple', the first item that evaluates as True, and
'' or [] or ()
returns (), even though it evaluates as False.
Extended and usage
For contrast, x and y returns x if bool(x) evaluates as False, else it returns y.
It makes sense that and would work this way when you consider that all of the conditions in a conditional and series needs to evaluate as True for the control flow to proceed down that path, and that it makes no sense to continue evaluating those items when you come across one that is False.
The utility of using and for assignment is not immediately as apparent as using or, but it was historically used for ternary assignment. That is, before this more clear and straightforward construction was available:
a = x if condition else y
the equivalent formed with boolean operators was:
a = condition and x or z # don't do this!
which while the meaning is derivable based on a full understanding of Python and and or evaluation, is not nearly as readable as the ternary conditional, and is best avoided altogether.
Conclusion
Using Boolean expressions for assignment must be done carefully. Definitely never use and for assignment, which is confusing enough to be quite error-prone. Style mavens will find use of or for assignments less preferable (than the more verbose ternary, if condition else), but I have found that it is so common in the professional Python community that it could be considered idiomatic.
If you choose to use it, do so cautiously with the understanding that the final element, if reached, will always be returned regardless of its evaluation, so that final element should probably be a literal, so that you know you have a good default fallback for your variable.

What is the motivation for the "or" operator to not return a bool?

First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.

sequences of condition checking

I am new the forum so hope this question is not too elementary or that it has been asked before. While writing some code in python, I found that individual functions (here called function1, function2 and function3) returning true or false would have the same output written to screen, and therefore I would like to link them together like this;
if function1 or function2 or function3:
print "something"
I know that function3 will take much more time to run, so I would like to avoid it. As the condition is now written it seems to me that it would be great for me if Python first evaluates function1 to false, and then stops the evaluation of the other conditions because it knows that the if-condition is already broken. The other possibility is that the returning values of all three functions are found separately before the truth value of the combined expression is evaluated. Does anybody know the sequences of action in the if condition-evaluation?
Python already does this for you with a mechanism known as "short-circuit" evaluation.
When a Boolean expression is found to be False (for an and) or True (for an or) at any stage during the evaluation, the rest of the expression is not evaluated since the end-result is already determined at that point.
So the order you put things into your Boolean expression really matters.
This is really quite useful since you can do something like this:
if i != 0 and 2332.0 / i:
...
to avoid division by zero with a simple and expression (i.e., the division will never take place if i is zero).
Also, note: You do need () for your function calls to work.
Finally, this short-circuiting evaluation isn't unique to Python, lots of languages do this.
What you're talking about is called "short-circuiting", and python does indeed do it.
However, I think if you want this to work properly, you want to use the and operator, not or as False or True returns True whereas False and True returns False (without ever looking at the second value). For completeness, True or False returns True (without ever looking at False).
Also, In your example, you're not actually calling the functions ... to call a function in python, you need parentheses:
function1(args) #for example

Categories