Python operator precedence

2019-02-21 18:50发布

问题:

Python docs say that * and / have the same precedence.
I know that expressions in python are evaluated from left to right.

Can i rely in that and assume that jj/m is always equal to (jj)/m avoiding the parentheses?
If this is the case can i assume that this holds for operators with the same precedence in general?


ps: The question as it is fine for my purposes, i came to it while reading integer-only code (like the above example) without parentheses, which at the time looked a lot suspicious to me.

回答1:

Yes - different operators with the same precedence are left-associative; that is, the two leftmost items will be operated on, then the result and the 3rd item, and so on.

An exception is the ** operator:

>>> 2 ** 2 ** 3
256

Also, comparison operators (==, >, et cetera) don't behave in an associative manner, but instead translate x [cmp] y [cmp] z into (x [cmp] y) and (y [cmp] z).



回答2:

But, if it is ambiguous to you - the coder - and it must be because you have to ask, then expect it will be at least as ambiguous for the reader and waste a couple octets for clarity.

Relying on precedence rules is great if you happen to be a compiler.

added responses to comments:

For the person reading code who encounters an ambiguity that requires outside consultation for assurance, you should assume that the next reader will be less savvy than you and save them the effort and avoidable human error of parsing the same construct and add the parenthesis for them.

As it happens, even the accepted answer was incorrect (in rationale, not effect, see its first comment) which I wasn't aware of and neither were a fraction of those who upvoted it.

As to the statement about basic algebra, the particular example used in the OP is instructive. Regardless of operator precedence the expression j * (j / m) is algebraically identical to (j * j) / m. Unfortunately, Python algebra is only an approximation of "Platonic ideal" algebra which could yield incorrect answers for either form depending on the magnitudes of j and m. For example:

>>> m = 1e306
>>> m
1e+306
>>> j = 1e307
>>> j
9.9999999999999999e+306
>>> j / m
10.0
>>> j*j
inf
>>> j * (j / m)
1e+308
>>> (j * j) / m
inf
>>> ((j * j) / m) == (j * (j/m))
False

So indeed the identity property of Python's (and my FPU) quasi-algebra doesn't hold. And this may be different on your machine for as the documentation notes:

Floating point numbers are implemented using double in C. All bets on their precision are off unless you happen to know the machine you are working with.

It could be claimed that one has no business working on the hairy edge of overflow, and that's true to some extent, but removed from context the expression is indeterminate given one order of operations and "correct" under another.



回答3:

Short answer: yes.

The Python documentation says the following:

Operators in the same box have the same precedence. Unless the syntax is explicitly given, operators are binary. 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... and exponentiation, which groups from right to left).

So in other words the answer to your question is yes, operators with the same precedence will group left to right apart from Comparisions which chain rather than group:

>>> x = 0
>>> y = 0
>>> x == y == True
False
>>> (x == y) == True
True
>>> x == (y == True)
True

and Exponentation:

>>> 2 ** 2 ** 3
256
>>> (2 ** 2) ** 3
64
>>> 2 ** (2 ** 3)
256

Also, in assignment the right-hand side is evaluated before the left-hand side:

>>> x = 1
>>> y = x = 2
>>> y
2