0

I was playing around with logical expressions in the python interpreter, and I can't seem to figure out what execution procedure python is really using under the hood. I've seen this table (http://www.mathcs.emory.edu/~valerie/courses/fall10/155/resources/op_precedence.html) as describing the operator precedence that python uses.

1)

print("this") or True and 1/0 and print("tester")

when I type that into the python interpreter I get the output of "this" and then zero division error. However, the site I referenced mention that function calls are the second highest precedence, so shouldn't both function calls of print be executed first? I know there's short circuit evaluation, but doesn't that kick in only once you get to the precedence level of the ands, nots, and ors?

2)

True>False or print("hello")

even this outputs only True on the python interpreter. why doesn't it do the function call of print first?

3)

5 is 5 or 1/0

This outputs True. But shouldn't division have higher precedence than "is" and shouldn't this expression return a ZeroDivsionError?

Can someone explain what I'm missing and how to tell in what order python will execute a logical expression?

  • 1
    From what I understand, precedence order does not mean evaluation order. Precedence is used by the parser to construct the parse tree (and then syntax tree or some IR). Again, that's just my understanding and I don't know if this is the case for Python too. – frederick99 Jun 28 '19 at 06:03
  • 1
    Precedence does not supersede logical operators/short circuiting. It just specifies with which precedence expressions are grouped together before being evaluated. – deceze Jun 28 '19 at 06:03
  • 1
    In `X or Y` and in `X and Y`, `X` is _always_ evaluated first, regardless of what operations are used inside `Y`. Otherwise short-circuiting would not be possible. – khelwood Jun 28 '19 at 06:03
  • since you already know about short-circuit evaluation, check this out https://stackoverflow.com/questions/46506098/why-does-short-circuit-evaluation-work-when-operator-precedence-says-it-shouldn – Arne Jun 28 '19 at 06:08
  • Ok I think I'm getting the hang of this, thanks guys! And thanks for pointing me to the answer @Arne , that made things a lot more clear – purplejackfruit Jun 28 '19 at 06:23
  • You are confusing operator precedence with order of evaluation. Operator precedence affects the evaluation order of *operators*. Not operands.Order of operand evaluation is either undefined or in some well-defined languages left to right. However, depending on the specification and the implementation, every operand can be evaluated before *any* operators are applied. – user207421 Jul 02 '19 at 09:58

3 Answers3

1

Precedence order is used by the parser to construct a parse tree. It does not mean the same as evaluation order.

Taking your 3rd case as an example: 5 is 5 or 1/0. The precedence order is / > is > or.

The parse tree would look something like this (according to the precedence.)

     or
   /    \
  is    div
 / \    / \
5   5  1   0

Evaluation (technically, code generation) starts from the top, in this case, the or node, according to another rule provided to the code generator. The output of a code generator for or may look something like this.

t = code(5 is 5)
if t goto L1
L2: code(1/0)
    goto L1
L1:

The precedence order was only used initially to create the parse tree. Once the parse tree is constructed, semantic rules (actions? i'm forgetting words) come into play.

The short circuit behavior is built into the or node's semantic rule.

p.s. This answer is not for Python specifically.

frederick99
  • 1,033
  • 11
  • 18
1

Can someone explain what I'm missing and how to tell in what order python will execute a logical expression?

Precedence affects which way "shared" operands will be grouped when parsing to a tree. Past that, the specific evaluation model of each sub-expression takes over.

print("this") or True and 1/0 and print("tester")

You get a tree which looks like this (you can get the more verbose but exact version using the ast module, and astpretty to get something readable):

    or
        print("this")
        and
             True
             and
                 1/0
                 print("tester")

Then evaluation takes over (after a compilation to bytecode but that doesn't change the order of operation):

  1. the outer or is evaluated
    1. it evaluates the first print, which returns a falsy value, therefore
    2. it evaluates the first and
      1. it evaluates True which is truthy
      2. therefore it evaluates the second and
        1. which evaluates 1/0 which blows up

True>False or print("hello")

This parses to

or
   >
      True
      False
   print("hello")
  1. or evaluates its first operand

    1. (> True False) evaluates to True

    or is a short-circuiting operator, it stops as soon as it finds a truthy value and returns that, so it never gets to the print

5 is 5 or 1/0

This parses to

or
    is
        5
        5
    /
        1
        0
  1. or is evaluated

    1. is is evaluated, and returns True

    as above, or is a short-circuiting operator and returns the first truthy value, so it returns immediately.

I left out some bits e.g. technically / evaluates both operands then applies its operation, function calls evaluate all their parameters then perform the call itself.

and and or stand out because they perform logic after the evaluation of each operand, not after having evaluated all of them (they're lazy / short-circuiting): and returns the first falsy result it gets, or returns the first truthy result it gets, potentially evaluating only the first of their operands.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Of course it can. Unlike most operators, "and" and "or" are the ones triggering the evaluation of their operands. Operand evaluation absolutely does not precede operator evaluation for their case, which is why is part of the reason why there is no data model hook for them. And why `1 or 1/0` executes just fine (it short-circuits after the first operand is evaluated) while `1 | 1/0` doesn't (both operands are evaluated and only then is the operator evaluated). In general you're correct, but you're specifically wrong for `and` and `or`, which is the entire point. – Masklinn Jul 02 '19 at 11:29
0

Precedence does not affect the order in which python evaluates statements. In 5 is 5 or 1/0, python first checks if 5 is 5 is true, and if it is, it ignores the second statement. In other words python always evaluates the first statement first, regardless of precedence

3NiGMa
  • 545
  • 1
  • 9
  • 24
  • This answer is dead flat wrong. *Statements* are evaluated in the order of their occurrence in the source file, subject to the semantics of method/function calls, conditional and looping statements, returns, and exceptions. Precedence doesn't affect the order of evaluation of operands *either*. It affects the order of evaluation of *operators.* – user207421 Jul 02 '19 at 09:56