<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Is this a bug or a feature?<br>
      Consider the following program:<br>
      <br>
      # TestProgram.py<br>
      def Test():<br>
        # global x<br>
          x = 1<br>
          exec(compile('print([x+1,x+2])', 'MyTest', 'exec'))<br>
          exec(compile('print([x+i for i in range(1,3)])', 'MyTest',
      'exec'))<br>
      Test()<br>
      <br>
      In Python 2.7.15 the output is<br>
      <br>
      [2, 3]<br>
      [2, 3]<br>
      <br>
      In Python 3.6.5 the output is<br>
      [2, 3]<br>
      Traceback (most recent call last):<br>
        File "TestProgram.py", line 7, in <module><br>
          Test()<br>
        File "TestProgram.py", line 6, in Test<br>
          exec(compile('print([x+i for i in range(1,3)])', 'MyTest',
      'exec'))<br>
        File "MyTest", line 1, in <module><br>
        File "MyTest", line 1, in <listcomp><br>
      NameError: name 'x' is not defined<br>
      <br>
      If the "global x" declaration is uncommented, this "fixes" the
      Python 3.6.5 behaviour,<br>
      i.e. no error occurs and the output is the same as for Python
      2.7.15.<br>
      <br>
      <b>In other words, it looks as if in Python 3.6.5, the compiled
        list comprehension</b><b><br>
      </b><b>can "see" a pre-existing global variable but not a local
        one.</b><br>
      <br>
      I have used dis to examine the code objects returned by compile()<br>
      (they are the same with or without the "global x"):<br>
      <br>
      Python 2.7.15 first code object from 'print([x+1,x+2])':<br>
        1           0 LOAD_NAME                0 (x)<br>
                    3 LOAD_CONST               0 (1)<br>
                    6 BINARY_ADD<br>
                    7 LOAD_NAME                0 (x)<br>
                   10 LOAD_CONST               1 (2)<br>
                   13 BINARY_ADD<br>
                   14 BUILD_LIST               2<br>
                   17 PRINT_ITEM<br>
                   18 PRINT_NEWLINE<br>
                   19 LOAD_CONST               2 (None)<br>
                   22 RETURN_VALUE<br>
      Python 2.7.15 second code object from 'print([x+i for i in
      range(1,3)])':<br>
        1           0 BUILD_LIST               0<br>
                    3 LOAD_NAME                0 (range)<br>
                    6 LOAD_CONST               0 (1)<br>
                    9 LOAD_CONST               1 (3)<br>
                   12 CALL_FUNCTION            2<br>
                   15 GET_ITER<br>
              >>   16 FOR_ITER                16 (to 35)<br>
                   19 STORE_NAME               1 (i)<br>
                   22 LOAD_NAME                2 (x)<br>
                   25 LOAD_NAME                1 (i)<br>
                   28 BINARY_ADD<br>
                   29 LIST_APPEND              2<br>
                   32 JUMP_ABSOLUTE           16<br>
              >>   35 PRINT_ITEM<br>
                   36 PRINT_NEWLINE<br>
                   37 LOAD_CONST               2 (None)<br>
                   40 RETURN_VALUE<br>
      Python 3.6.5 first code object from 'print([x+1,x+2])':<br>
        1           0 LOAD_NAME                0 (print)<br>
                    2 LOAD_NAME                1 (x)<br>
                    4 LOAD_CONST               0 (1)<br>
                    6 BINARY_ADD<br>
                    8 LOAD_NAME                1 (x)<br>
                   10 LOAD_CONST               1 (2)<br>
                   12 BINARY_ADD<br>
                   14 BUILD_LIST               2<br>
                   16 CALL_FUNCTION            1<br>
                   18 POP_TOP<br>
                   20 LOAD_CONST               2 (None)<br>
                   22 RETURN_VALUE<br>
      Python 3.6.5 second code object from 'print([x+i for i in
      range(1,3)])':<br>
        1           0 LOAD_NAME                0 (print)<br>
                    2 LOAD_CONST               0 (<code object
      <listcomp> at 0x00000000029F79C0, file "MyTest", line 1>)<br>
                    4 LOAD_CONST               1 ('<listcomp>')<br>
                    6 MAKE_FUNCTION            0<br>
                    8 LOAD_NAME                1 (range)<br>
                   10 LOAD_CONST               2 (1)<br>
                   12 LOAD_CONST               3 (3)<br>
                   14 CALL_FUNCTION            2<br>
                   16 GET_ITER<br>
                   18 CALL_FUNCTION            1<br>
                   20 CALL_FUNCTION            1<br>
                   22 POP_TOP<br>
                   24 LOAD_CONST               4 (None)<br>
                   26 RETURN_VALUE<br>
      <br>
      You will see that in Python 3.6.5 the dis output for the second
      code object<br>
      does not show the internals of the listcomp, and in particular
      whether,<br>
      and how, it refers to the variable 'x'.  I don't know how to
      investigate further.<br>
      <br>
      Best wishes<br>
      Rob Cliffe<br>
    </p>
  </body>
</html>