2

I'd like this question answered just for curiosity's sake. In the following mathematical expression (and ones like it):

(( (3 * 7)  + 5 * ((3 - 7) + (3 * 4))) + 9)

Does Python evaluate (3 - 7) or (3 * 4) first? The thing about this is, these innermost parentheses could really be evaluated in either order and achieve the same result. But which order is used?

At this point I'm considering putting a breakpoint in the actual Python interpreter to see if I can come up with any sort of answer (as to how the parse tree is generated). Been asking on IRCs and such to no avail. Thanks for your time.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 1
    Such a literal expression isn't evaluated by Python at all. It is directly compiled to the result. – MisterMiyagi Jan 23 '20 at 15:13
  • @MisterMiyagi - could we say instead that it must be read by the interpreter in some order? – James Erickson Jan 23 '20 at 15:17
  • 2
    @Someprogrammerdude The question states clearly that is `just for curiosity's sake` – Valentin M. Jan 23 '20 at 15:17
  • Have your read the documentation on [Operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence)? – martineau Jan 23 '20 at 15:20
  • There's a very big difference how an expression is parsed by the compiler, how the compiler generates the parse-tree, how code is generated from a parse tree, and how the generated code is executed. Asking for answers to more than one of those will make the question too broad and unfocused. – Some programmer dude Jan 23 '20 at 15:20
  • @Someprogrammerdude Then, I'll edit it to ask specifically how it generates the parse-tree. – James Erickson Jan 23 '20 at 15:22
  • 1
    @JamesErickson Are you really interested in the *parse tree generation*? That is highly implementation specific and has no bearing on the evaluation at runtime. – MisterMiyagi Jan 23 '20 at 15:32
  • I am interested in that, yes. But the fact that it is implementation specific is probably enough to know for now haha. I can look into it more later. – James Erickson Jan 23 '20 at 15:33
  • @martineau: To be clear, the question being asked here isn't about operator precedence, but expression evaluation order. Operator precedence wouldn't affect whether `(3 - 7)` or `(3 * 4)` was loaded or computed first (you could load `3` & `4` and multiply, then load `3` and `7` and subtract, or vice-versa, and the `+` between them would still get the same result). Expression evaluation order rules (which are often underspecified in low-level languages) are what determines which values and expressions must be computed, in what order (Python is very strict about it). – ShadowRanger Jun 16 '22 at 15:07

2 Answers2

8

You can inspect the byte code to see that the left side is evaluated first:

dis.dis("""(a - b) + (c * d)""")
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 BINARY_SUBTRACT
              6 LOAD_NAME                2 (c)
              8 LOAD_NAME                3 (d)
             10 BINARY_MULTIPLY
             12 BINARY_ADD
             14 RETURN_VALUE

The evaluation order of expressions is part of the language specification.

Evaluation order

Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.


Note that if you use a literal expression, such as (3 - 7) + (3 * 4), it is not evaluated but directly compiled.

dis.dis("""(3 - 7) + (3 * 4)""")
  1           0 LOAD_CONST               0 (8)
              2 RETURN_VALUE
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • 1
    yah +1, very clear, but why the caveat about CPython/PyPy, this is surely language specification not implementation specific? – Chris_Rands Jan 23 '20 at 15:20
  • @Chris_Rands My bad, I confused that with the evaluation order of statements (which isn't explicitly specified, strangely). I've replaced the part with a link to the documentation. – MisterMiyagi Jan 23 '20 at 15:28
  • @MisterMiyagi: The evaluation order of statements is specified on a case by case basis. Your own quote for instance notes that the assignment statement fully evaluates the right side before it begins evaluating (including the actual assignments to) the left side. The assignment statement docs further clarify that multiple targets, and unpacking targets, assign left-to-right (like expressions), e.g. `a = b, c[b] = 1, 2` assigns `(1, 2)` to `a` first, then assigns `1` to `b`, then assigns `2` to `c[b]` (and because `b` is assigned first, it's assigning to `c[1]`, ignoring any prior `b` value). – ShadowRanger Jun 16 '22 at 15:02
  • @ShadowRanger What I mean is that the "top-down" evaluation order between statements doesn't seem to be specified. – MisterMiyagi Jun 16 '22 at 15:58
  • @MisterMiyagi: Not sure I understand. Are you asking if the spec guarantees that statements execute in the same order as seen in the source code? Simple statements, by definition, do not compose (you can't have a statement made up of multiple statements) so evaluation order between statements isn't a thing, unless you're considering the possibility of statement reordering, as might be done by a C/C++ compiler. Compound statements (block statements like `if`) do contain other statements, but by definition the compound statement itself must be executed before the suite of statements it contains. – ShadowRanger Jun 16 '22 at 18:39
  • @ShadowRanger Not sure what is the correct wording since I didn't find anything on it back when I wrote the answer. Your first point about executing in the same order as in the source code - with the exceptions for statements that consume their suites unevaluated and declarations - should be it. While I would say the evaluation order is "obvious" (at least for standard cases) it was odd not finding anything on it. – MisterMiyagi Jun 17 '22 at 07:35
1

It evaluates left-to-right, you can check with with input() calls:

>>> (( (3 * 7) + 5 * ((input('1')) + (input('2')))) + 9)
1
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119