Precedence of operators in python [duplicate] - python

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.

Related

Why only first or second operand gets printed? [duplicate]

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.

Python precedence 1 < 0 == 0 --> False [duplicate]

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.

Is there a faster way to know if it's a real triangle?

The following code is intended to return 0 if it's not possible to form a triangle with three given sides and return 1 if it is possible. Taking into account that it's not possible for a triangle to have an area of zero or less, first I calculated the semiperimeter of this hypothetical triangle and then return 1 if the result is greater than the greatest value in the given list. I did the previous because if the semiperimeter is less than the greatest value in the list, then when calculating the area with the Heron formula it would be an undefined root.
def isTriangle(aList):
semiperimeter = (aList[0] + aList[1] + aList[2]) / 2
if semiperimeter > max(aList):
return 1
else:
return 0
So I want to know if there is a faster way in Python to perform this (or at least with fewer lines of code).
You can check if the sum of the two smaller sides is at least as large as the longest side:
def check(aList)
return sum(aList) - max(aList) > max(aList)
With python 3.8+, you can avoid recomputing the maximum twice using a walrus operator:
def check(aList):
return (m := max(aList)) < sum(aList) - m
Both solutions rely on numerical comparisons returning a big boolean. In python bool is a subclass of int that has only two possible singleton values: True == 1 and False == 0. It's standard to return a bool rather than 0 or 1 for something like this. In fact, your original conditional could be replaced by
return semiperimeter > max(aList)
Or, absorbing the previous line into the return:
return sum(aList) / 2 > max(aList)
You could also write
return sum(aList) > 2 * max(aList)
This version avoids any type conversions, regardless if whether you pass in floats or integers (/ 2 always results in a float).
You asked for shorter code. That one is possible to do as a oneliner.
def isTriangle(aList):
return ((aList[0] + aList[1] + aList[2]) / 2) > max(aList) and 1 or 0
Exatly the same code, but just written shorter
To determine if given 3 sides can form a valid triangle, I would suggest using Triangle Inequality Theorem. It roughly states that the sum of any two sides must always be equal or greater than the other side to be able to form a valid triangle.
Therefore, I would instead write something along this line. [Edited: initialization according to Avinash]
def isTriangle(aList):
a,b,c = aList
return (a + b >= c and a + c >= b and b + c >= a)
In case you really want to make it return 0 or 1 instead of boolean then you can use this return instead.
return 1 if a + b >= c and a + c >= b and b + c >= a else 0

Python - why '&' and 'and' operators provide different results though evaluate the condition with same result

I have just started learning Python. I have come across the below problem. As shown below, I am writing a same statement once using '&' operator and then using 'and' operator. Though both of these operators evaluate the 'if' condition to the same Boolean output,'True' (True 'and' True is True and also True & True is True), why are the results different? Why is '&' giving wrong answer? Appreciate any clarifications.
a = 70
b = 40
c = 60
x = a if a>b and a>c else b if b>c else c
print('Max value with "and":', x)
x = a if a>b & a>c else b if b>c else c
print('Max value with "ampersand":', x)
The output is:
Max value with "and": 70
Max value with "ampersand": 60
why are the results different? Why is '&' giving wrong answer?
Because they're completely different operators with completely different semantics and completely different precedence: & applies before > which applies before and.
So when you write a > b and a > c it's parsed as (a > b) and (a > c).
But when you write a > b & a > c, it's parsed as a > (b & a) > c.
There's an other difference which is not relevant here but would be a factor in other context: and (and or) are lazy operators, meaning they will evaluate their left operands, then do their thing, and only then evaluate the second operand. & however is a normal "eager" operator, it evaluates both operands and only then applies whatever it does.
Finally, and this is of course the biggest difference: and works on everything and is non-overridable; & only works on types which specifically support it, and does whatever it was defined as (for integers it's a bitwise AND, but for sets it's intersection).

Python Operators: Math Precedence Comparison operators vs equality operators

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.

Categories