Logical operators in Python [duplicate] - python

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed last month.
While reading about logical operators in python, I came across the following expressions:
5 and 1
output: 1
5 or 1
output: 5
Can anyone explain how this is working?
I know that the operands of the logical operators are Boolean

that is well documented:
x or y if x is false, then y, else x
x and y if x is false, then x, else y
both short-circuit (e.g. or will not evaluate y if x is truthy).
the documentation also states what is considered falsy (False, 0, None, empty sequences/mappings, ...) - everything else is considered truthy.
a few examples:
7 and 'a' # -> 'a'
[] or None # -> None
{'a': 1} or 'abc'[5] # -> {'a': 1}; no IndexError raised from 'abc'[5]
False and 'abc'[5] # -> False; no IndexError raised from 'abc'[5]
note how the last two show the short-circuit behavior: the second statement (that would raise an IndexError) is not executed.
your statement that the operands are boolean is a bit moot. python does have booleans (actually just 2 of them: True and False; they are subtypes of int). but logical operations in python just check if operands are truthy or falsy. the bool function is not called on the operands.
the terms truthy and falsy seem not to be used in the official python documentation. but books teaching python and the community here do use these terms. there is a discussion about the terms on english.stackexchange.com and also a mention on wikipedia.

This is because of the short-circuit evaluation method.
For the and, all of the clauses must be True, so all of them must be evaluated. Once a False is encountered, the whole thing evaluates to False, we don't even need to evaluate the next ones.
>>> 1 and 2
2
>>> 2 and 1
1
>>> 1 and 2 and 3
3
>>> 1 and 0 and 2
0
>>> 0 and 1 and 2
0
But for or, any of the clauses being evaluated to True is enough for the whole thing to be True. So once it finds something to be True, the value of the whole thing is decided to be True, without even evaluating the subsequent clauses.
>>> 0 or 1
1
>>> 1 or 0
1
>>> 1 or 2
1
>>> 2 or 1
2
>>> 0 or 0 or 1
1
>>> 0 or 1 or 2
1

This is called short circuiting or lazy evaluation. Example, if you have "a or b" and a meets the criteria, then python will output it. Conversely, if you have "a and b" and "a" does not meet the criteria, then python will stop evaluating it since it cannot be satisfied.

In the first case when the and keyword is there, it is the second value that determines whether it is logically true or not, provided the first number is non-zero. Thus the second value is printed eventually.
In the second case, the keyword is or so when the first non-zero operand is encountered, since it makes the statement logically true, it is printed onto the output screen.
It is an example of lazy evaluation.

Related

Why does Python switch from 1 or 0 to True or False?

I'm learning about logic gates and was messing around with them when I found something interesting. This is my code:
for i in range (4):
p = math.floor(i/2)
q = i % 2
a = p and q
b = not(not(p or q) or not(q) or not(p))
print(str(p) +"\t"+ str(q) + "\t"+ str(a)+"\t"+str(b))
And this is the result:
0 0 0 False
0 1 0 False
1 0 0 False
1 1 1 True
Why doesn't Python either always print a 1 or a 0 or always print True or False?
math.floor returns a number.
Operators between two numbers (such as modulo) also return numbers.
not returns a bool, not an int
Because not has to create a new value, it returns a boolean value regardless of the type of its argument - spec
If you want it to be an int (and simplify the print statement)
print('\t'.join(map(str, [p, q, a, int(b)])
The not unary operator always returns a bool value. It needs to, as it needs to return the boolean inverse of whatever value it was passed, which is always a new value (not its argument).
The real odd part of your chart is actually the third column, which shows that the and operator does return numbers if it's passed them on both sides. You might expect and to be a boolean operator just like not, but it's slightly different. The reason is that and always returns one of its arguments. If the first argument is falsey, that value is what is returned. If the first argument is truthy, the second argument is returned.
You can see this if you test with values other than just 0 and 1:
print(3 and 2) # prints 2
print([] and [1,2]) # prints []
The or operator also does this (in a slightly different manner), but that's covered up in your calculation of b by the not calls.
This behavior of and and or is called short-circuiting. It's big advantage is that it lets Python avoid interpreting expressions it doesn't need to get the value of the boolean expression. For instance, this expression will not call the slow_function:
result = falsey_value and slow_function()
It also lets you guard expressions that would cause exceptions if they were evaluated:
if node is not None and node.value > x:
...
If the node variable is None in that code, evaluating node.value would give an AttributeError (since None doesn't have a value attribute). But because and short circuits, the first expression prevents the second expression from being evaluated when it's invalid.

Why 'and' and 'or' behaves differently with 0, 1, True, False? [duplicate]

This question already has answers here:
Using "and" and "or" operator with Python strings
(6 answers)
Why do 'and' & 'or' return operands in Python?
(4 answers)
Closed 5 years ago.
Below is the scenario.
>>> False and 0
=> False
>>> 0 and False
=> 0
Both the conditions are same, but why is it returning different results?
>>> 0 or False
=> False
>>> False or 0
=> 0
Similarly, both the conditions should return same results, but why are they different?
The same applies in case of True and 1
In python, theand, or operators do not return boolean. They return the last thing evaluated. Since they are short circuit operators, the last thing that need to be evaluated for the expression 0 and False, is0. Similarly, for 0 or False, the last thing that needs to be checked is the second operand, False.
From the python documentation:
x or y: if x is false, then y, else x
x and y: if x is false, then x, else y
not x: if x is false, then True, else False
Python conditional checking uses Short-Circuit Evaluation. This means the following:
False and 0
It is executing an and statement, so both elements must evaluate to 1. Since False doesn't, it does not check for the second one and it returns False. This also applies for 0 and False, but since 0 is the first element it returns 0.
False or 0
In this case it is performing an or evaluation so one of the elements must evaluate to 1 (or True). Since False doesn't, it checks for the second operator (0) which neither evaluates to 1, so it returns it. The same applies for 0 or False.
Here you have another approach that clears out any doubt. Using 0 or "Text" it returns "Text" as it evaluates to True.
or is a short-circuit operator, so it only evaluates the second argument if the first one is false. In the case, False or 0, first argument is evaluated to False, then second argument is evaluated, which is 0, and returns 0. This is valid for both the cases(0 or False too).
and is also a short-circuit operator, so it only evaluates the second argument if the first one is true. In the case False and 0, the first argument is evaluated to False, then the second is not evaluated and returns the first argument and vice versa.
For more clarification, refer the docs.

Exception with 0 in comparison

Hey my question is pretty basic, while I was playing around in the expresssion
3 and 3%3 == False returns True
BUT
0 and 0%3 == False returns 0
With other numbers instead of 0 the result is either True or False but never 0.
I wanted to know what does make 0 so special.
From all integers, 0 is the only one that is evaluated to False. In fact, False's value is 0 (you can try print False + 0) - so you get the second expression's result (X % Y == Z which is True/False).
Any other integer and the first argument is what is returned (int) since and stops and returns the first expression false-y expression (there is no need to proceed once you hit a single False in an and expression). It does not matter what the next expression is since it's never even evaluated.
First, 3%3 is equal to 0. Next, bool is a subclass of int, with 0==False and 1==True. Then, you have 3 and 3%3==False, which is 3 and 0==False, which is 3 and True.
So now that leaves us with the way short-circuiting works: with and, if the first value is falsey, it returns the first value. If the first value is truthy, it returns the second value. Since 3 is truthy, it returns the second value, True.
3 and 3%3==False
3 and 0==False
3 and True
^ truthy
3 and True
^ returned
For the next one, 0%3 is the same 0 as in the previous one, which turns out the same. However, the first value, 0, is a falsey value, so, since it's combined with and, the first value, 0, is returned.
0 and 0%3==False
0 and 0==False
0 and True
^ falsey
0 and True
^ returned
TLDR: Boolean operators in Python evaluate to the first value that unambiguously determines their value.
So, let's look at 3 and 3 % 3 == False, which is equivalent to 3 and ((3 % 3) == False). An and expression has a boolean value of True only if both the values have a boolean value of True; otherwise it has a boolean value of False. First it checks 3, which returns 3, which has a boolean value of True (bool(3) is True). Then it checks (3 % 3) == False, which returns True, which of course has a boolean value of True. Now that the right side of the and has also been shown to have a boolean value of True, that's what is 'returned' by the and expression.
The reason that 0 and 0 % 3 == False returns 0 is because the first value in the and expression is checked first. Since the first value is 0, which has a boolean value of False, there's no need to check the rest of the and expression. So 0 is returned by the and expression.
Here's some code:
>>> x = 5 or 3
>>> print(x)
5
>>>
>>> y = 0 and 7
>>> print(y)
0
>>>
>>> z = 1 and 7
>>> print(z)
7

Why do 'and' & 'or' return operands in Python?

I'm going through the LPTHW and I came across something I cannot understand. When will it ever be the case that you want your boolean and or or to return something other than the boolean? The LPTHW text states that all languages like python have this behavior. Would he mean interpreted vs. compiled languages or duck typed vs static typed languages?
I ran the following code:
>>> False and 1
False
>>> True and 1
1
>>> 1 and False
False
>>> 1 and True
True
>>> True and 121
121
>>> False or 1
1
>>> False or 112
112
>>> False or "Khadijah"
'Khadijah'
>>> True and 'Khadijah'
'Khadijah'
>>> False or 'b'
'b'
>>> b = (1, 2, "K")
>>> b
(1, 2, 'K')
>>> False or b
(1, 2, 'K')
>>>
Please help me understand whats going on here.
According to the documentation: http://docs.python.org/2/library/stdtypes.html
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)
According to LPTHW: http://learnpythonthehardway.org/book/ex28.html
Why does "test" and "test" return "test" or 1 and 1 return 1 instead of True?
Python and many languages like it return one of the operands to their boolean expressions rather than just True or False. This means that if you did False and 1 you get the first operand (False) but if you do True and 1 your get the second (1). Play with this a bit.
I think you're somehow confused about what the docs says. Take a look at these two docs sections: Truth Value Testing and Boolean Operators. To quote the last paragraph on the fist section:
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)
As you can see, you're right about operations and built-in functions but see the Important exception part, it is well stated that the Boolean operators will return one of their operands.
Now, what they can return depends hardly on the operator's short circuit logic. For or operator, it will return the first truthy value in the expression, since when it finds one, the whole expression is true. In case of every operand being falsey, or will return the last operand, meaning that it iterated over every one of them not being able to find a truthy one.
For and operator, if the expression is true, it will return the last operand, if the expression is false, it will return the first falsey operand. You can read more about Short Circuit Evaluation at the Wikipedia Page.
You have a lot of examples in your question, let's analyze some of them:
>>> False and 1 # return false (short circuited at first falsey value)
False
>>> True and 1 # return 1 (never short circuited and return the last truthy value)
1
>>> 1 and False # return false (short circuited at first falsey value, in this case the last operand)
False
>>> 1 and True # return True (never short circuited and return the last truthy value)
True
>>> True and 121 # return 121 (never short circuited and return the last truthy value)
121
>>> False or 1 # return 1 (since the first operand was falsey, or kept looking for a first truthy value which happened to be the last operator)
1
>>> False or 112 # return 112 for same reason as above
112
>>> False or "Khadijah" # return "Khadijah" for same reason as above
'Khadijah'
>>> True and 'Khadijah' # return "Khadijah" because same reason as second example
'Khadijah'
I think this should make a point. To help you further understand why this is useful, consider the following example:
You have a function that randomly generate names
import random
def generate_name():
return random.choice(['John', 'Carl', 'Tiffany'])
and you have a variable that you don't know if it has assigned a name yet so instead of doing:
if var is None:
var = generate_name()
You can do oneliner:
var = var or generate_name()
Since None is a falsey value, or will continue its search and evaluate second operand, this is, call the function ultimately returning the generated name. This is a very silly example, I have seen better usages (although not in Python) of this kind of style. I couldn't come out with a better example right now. You can also take a look at this questions, there are very useful answers on the topic: Does Python support short-circuiting?
Last but not least, this has nothing to do with static typed, duck typed, dynamic, interpreted, compiled, whatever language. It's just a language feature, one that might come handy and that is very common since almost every programming language I can think of provide this feature.
Hope this helps!
One would want and and or to evaluate to an operand (as opposed to always evaluating to True or False) in order to support idioms like the following:
def foo(self):
# currentfoo might be None, in which case return the default
return self.currentfoo or self.defaultfoo()
def foobar(self):
# foo() might return None, in which case return None
foo = self.foo()
return foo and foo.bar()
You can of course question the value of such idioms, especially if you aren't used to them. It's always possible to write equivalent code with an explicit if.
As a point against them, they leave some doubt whether the full range of falsey values is possible and intentionally accounted for, or just the one mentioned in the comment (with other falsey values not permitted). But then, this is true in general of code that uses the true-ness of a value that might be something other than True or False. It occasionally but rarely leads to misunderstandings.
This has to do with the way short circuit effect is implemented in Python.
With and (remember True and X = X), the result of the right expression is pushed into the stack, if it's false, it gets poped immediately, else the second expression is poped:
>>> import dis
>>>
>>> dis.dis(lambda : True and 0)
1 0 LOAD_CONST 2 (True)
3 JUMP_IF_FALSE_OR_POP 9
6 LOAD_CONST 1 (0)
>> 9 RETURN_VALUE
>>>
>>> True and 0
0
>>> 0 and True
0
>>>
similar to:
def exec_and(obj1, obj2):
if bool(obj1) != False:
return obj2
return obj1
With or, if the first expression is true, it gets popped immediately. If not, the second expression is poped, now the result really depends on the second.
>>> dis.dis(lambda : 0 or False)
1 0 LOAD_CONST 1 (0)
3 JUMP_IF_TRUE_OR_POP 9
6 LOAD_CONST 2 (False)
>> 9 RETURN_VALUE
>>>
>>> True or 0
True
>>> 1 or False
1
>>> False or 1
1
>>>
similar to:
def exec_or(obj1, obj2):
if bool(obj1) != True:
return obj2
return obj1
Consider the following use case:
element = dict.has_key('foo') and dict['foo']
Will set element to dict['foo'] if it exists, otherwise False. This is useful when writing a function to return a value or False on failure.
A further use case with or
print element or 'Not found!'
Putting these two lines together would print out dict['foo'] if it exists, otherwise it will print 'Not found!' (I use str() otherwise the or fails when element is 0 (or False) because that s considered falsey and since we are only printing it doesn't matter)
This can be simplified to
print dict.has_key('foo') and str(dict['foo']) or 'Not found!'
And is functionally equivalent to:
if dict.has_key('foo'):
print dict['foo']
else:
print 'Not found!'

and / or operators return value [duplicate]

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 4 years ago.
I was watching a 2007 video on Advanced Python or Understanding Python, and at 18'27" the speaker claims "As some may know in Python and and or return one of the two values, whereas not returns always a boolean." When has this been the case?
As far as I can tell, and and or return booleans, too.
The and and or operators do return one of their operands, not a pure boolean value like True or False:
>>> 0 or 42
42
>>> 0 and 42
0
Whereas not always returns a pure boolean value:
>>> not 0
True
>>> not 42
False
See this table from the standard library reference in the Python docs:
from Python docs:
The operator not yields True if its argument is false, False otherwise.
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Python's or operator returns the first Truth-y value, or the last value, and stops. This is very useful for common programming assignments that need fallback values.
Like this simple one:
print my_list or "no values"
This will print my_list, if it has anything in it. Otherwise, it will print no values (if list is empty, or it is None...).
A simple example:
>>> my_list = []
>>> print my_list or 'no values'
no values
>>> my_list.append(1)
>>> print my_list or 'no values'
[1]
The compliment by using and, which returns the first False-y value, or the last value, and stops, is used when you want a guard rather than a fallback.
Like this one:
my_list and my_list.pop()
This is useful since you can't use list.pop on None, or [], which are common prior values to lists.
A simple example:
>>> my_list = None
>>> print my_list and my_list.pop()
None
>>> my_list = [1]
>>> print my_list and my_list.pop()
1
In both cases non-boolean values were returned and no exceptions were raised.
Need to add some points to the #Frédéric 's answer.
do return one of their operands???
It is True but that is not the logic behind this. In python a number except 0 is considered as True and number 0 is considered as False.
(0 and 42 -> False and True) = False.
That's why it returns 0.
(0 or 42-> false or True) = 42
In that case the statement will be True because of the operand 42. so python returns the operand which causes the statement to be true, in that case.

Categories