print 1>0 == (-1)<0 # => False
print (1>0) == ((-1)<0) # => True
First line prints False.
Second line prints True
The problem is if according to the order comparison operators are above equality operators.
Shouldn't both lines print True? (Or at least the same thing..)
https://www.codecademy.com/en/forum_questions/512cd091ffeb9e603b005713
Both equality and the greater than and less than operators have the same precedence in Python. But you're seeing something odd because of how an expression with multiple comparison operators in a row gets evaluated. Rather than comparing the results of previous calculations using its rules of precedence, Python chains them together with and (repeating the middle subexpressions).
The expression 1 > 0 == -1 < 0 is equivalent to (1 > 0) and (0 == -1) and (-1 < 0) (except that each of the repeated subexpressions, like -1 only gets evaluated once, which might matter if it was a function call with side effects rather than an integer literal). Since the middle subexpression is False, the whole thing is False.
In the second version, the parentheses prevent the comparison chaining from happening, so it just evaluates the inequalities independently and then compares True == True which is True.
Related
I've been tinkering a little with Python operators and came across something I'm not sure about.
If I perform a bitwise operation (&, |) on 2 integers I will get unsurprisingly their bitwise value.
Meaning:
>>> a = 11
>>> b = 3
>>> a & b
3
This is because it performs bitwise AND on the binary representation of these numbers.
However, if I use the built in and operator I will get the second variable, irrespective of its type:
>>> b and a
11
>>> 'b' and 'a'
'a'
Why is it so?
Logical operators operate on the truthiness of an object. Every object has truth value, unless it has a __bool__ method that is explicitly overridden to raise an error. The major difference between a and b (logical) and a & b (bitwise) is that the former apply to any objects, while the latter only apply to numeric types that support bitwise operations1.
Python's logical operators are specifically designed to return the result of the last object evaluated:
a and b: Returns a Falsy a, or b (if a is truthy)
a or b: Returns a Truthy a, or b (if a if falsy)
From the tutorial:
The Boolean operators and and or 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.
This property is used semi-idiomatically to check values before accessing them. For example, if a list must contain an element, you can do something like
if x and x[0] == value:
# ...
This will not raise an error, because if x is Falsy (empty), the and expression will return x instead of x[0] == value.
1 Set-like objects also support & as the intersection operator. This is conceptually similar to what the bitwise operator does for integers (you can think of bits as sets), and in no way detracts from the rest of the answer.
The documentation says:
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.
Since Python considers the boolean value for both strings and non-zero integers to be True, x and y would imply True and True, and since the boolean of the first statement is not False, the second statement is evaluated and the resulting value (which is the value of the second term) is returned.
The first case with and:
>>> b and a #(11 and 3, both the values evaluates to be true because non-zero)
11
>>> 'b' and 'a' #(again both are evaluated to be true because non-empty)
For and all the conditions need to be True, so checked upto the last item if the previous evaluates to be True, hence you get the last item.
Case 1 : A and B
here consider A ,B both are non zeroes for and it checks both A,B that is it first evaluates A if in A after conversion in binary(for understanding consider positive integers , A > 0 and B > 0) whether 1 is present or not , if yes it moves to B and returns B as output. Because and checks both A and B.
A or B
here it checks the A as same as above if it has 1 after converting in to binary,
if A is True it return A (obviously A > 0 so it return A only ).
case 2 : suppose Any 1 in A,B or both A,B are ZEROES
I will try to explain in better way . I hope we all know truth tables for 'AND' and 'OR' and 'XOR'.
Same thing happening here just replace 1's and 0's with any number, if you want you use only 1's and 0's to understand in better way.
The Python documentation for operator precedence states:
Operators in the same box group left to right (except for
comparisons, including tests, which all have the same precedence and
chain from left to right — see section Comparisons...)
What does this mean? Specifically:
"Operators in the same box group left to right (except for
comparisons...)" -- do comparisons not group left to right?
If comparisons do not group left to right, what do they do instead? Do they "chain" as opposed to "group"?
If comparisons "chain" rather than "group", what is the difference between "chaining" and "grouping"?
What would be some examples to demonstrate that the comparison operators chain from left to right rather than from right to left?
Grouping (this is what non-comparison operators do):
a + b + c means (a + b) + c
Chaining (this is what comparison operators do):
a < b < c means (a < b) and (b < c)
Grouping left to right (this is the way things are grouped):
5 - 2 - 1 means (5 - 2) - 1 == 2
as opposed to grouping right to left (this would produce a different result):
5 - (2 - 1) == 4
Chaining left to right
Chaining is left to right, so in a < b < c, the expression a < b is evaluated before b < c, and if a < b is falsey, b < c is not evaluated.
(2 < 1 < f()) gives the value False without calling the function f, because 2 < 1 evaluates to false, so the second comparison does not need to be performed.
f() > 1 > g() calls f() in order to evaluate the first comparison, and depending on the result, it might or might not need to evaluate the second condition, which requires calling g().
NB. Each operand is evaluated at most once. So in the expression 1 < f() < 2, the function f() is only called once, and the value it gives is used in both comparisons (if necessary).
https://en.wikipedia.org/wiki/Short-circuit_evaluation
In fact, the chain behavior is not so obvious.
a == b == c
although one would expect this to be converted to
a == b and b == c
it is in fact converted into somthing similar to
b == c if a == b else False
which is a bit confusing if one tries to override the behavior of the comparison operators and chain them.
All comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Thus "==" and "<" have the same priority, why would the first expression in the following evaluate to True, different from the 2nd expression?
>>> -1 < 0 == False
True
>>> (-1 < 0) == False
False
I would expect both be evaluated to False. Why is it not the case?
Python has a really nice feature - chained comparison, like in math expressions, so
-1 < 0 == False
is actually a syntactic sugar for
-1 < 0 and 0 == False
under the hood.
print 1>0 == (-1)<0 # => False
print (1>0) == ((-1)<0) # => True
First line prints False.
Second line prints True
The problem is if according to the order comparison operators are above equality operators.
Shouldn't both lines print True? (Or at least the same thing..)
https://www.codecademy.com/en/forum_questions/512cd091ffeb9e603b005713
Both equality and the greater than and less than operators have the same precedence in Python. But you're seeing something odd because of how an expression with multiple comparison operators in a row gets evaluated. Rather than comparing the results of previous calculations using its rules of precedence, Python chains them together with and (repeating the middle subexpressions).
The expression 1 > 0 == -1 < 0 is equivalent to (1 > 0) and (0 == -1) and (-1 < 0) (except that each of the repeated subexpressions, like -1 only gets evaluated once, which might matter if it was a function call with side effects rather than an integer literal). Since the middle subexpression is False, the whole thing is False.
In the second version, the parentheses prevent the comparison chaining from happening, so it just evaluates the inequalities independently and then compares True == True which is True.
I want to write this if statement as compact as possible (to avoid having duplicate code)
if length == 10 if boolean is False or length == 13 if boolean is True:
The part that PyCharm does not like is the
if boolean is True
It asks for a colon.
PyCharm does not allow me to run it. Does anyone have a nice compact solution to this if?
I think you meant
if (not boolean and length == 10) or (boolean and length == 13):
The parentheses aren't necessary, but I think they help readability. #jonsharpe's solution is even shorter and only has to evaluate boolean once, but it may be harder to read, especially if you're not familiar with Python's ternary expressions.
Never use is for equality comparison (that's what == is for), but boolean types should never be explicitly compared to True or False anyway.
You can use a conditional expression (also known as a "ternary") to write it out much more concisely:
if length == 13 if boolean else length == 10:
or, equivalently:
if length == (13 if boolean else 10):
Per the documentation:
The expression x if C else y first evaluates the condition, C (not x); if C is true, x is evaluated and its value is returned; otherwise, y is evaluated and its value is returned.