[Python-bugs-list] Exec statement inconsistency (PR#175)

tim_one@email.msn.com tim_one@email.msn.com
Mon, 10 Jan 2000 02:36:16 -0500 (EST)


[Vadim Chugunov]
> Consider this code:
>     x = 1
>     exec "x=x+1"
>     print x
> The result is 2. On the other hand,
>     def f():
>         x=x+1
>     exec f.func_code
> results in NameError: x
> Exec on files is broken as well.

Vadim, I think Guido's out of town for a while.  This is a delicate area of
the interpreter and I doubt he'll be willing to make fundamental changes in
what it does.

For starters, the NameError above has nothing to do with exec.  You get the
same error if you call f() directly (in the current CVS version of Python,
it raises the more descriptive UnboundLocalError instead).  This is by
design:  "the rules" say that x is a local name in f(), and the code
attempts to reference its value before x has been bound.  If you change f to

def f():
    global x
    x = x+1

then it works as you hope whether called directly or via exec.  BTW, if it
wasn't clear, you don't get the error when you run the code at module level
because the locals and globals are the same namespace there.

> As far as I can see, the problem is that:
> a) PyFrame_New() ignores the locals passed in if the
> code object has the CO_NEWLOCALS flag set.
>
> b) exec_statement() does not call PyFrame_LocalsToFast() unless
> a string is being executed.

It's been a long time since I thought I understood all the rules here --
there are subtleties.  Still, it looks odd to me too that e.g.

def f():
    x = 1
    exec "x=x+1"
    print x     # prints 2

def g():
    x = 1
    exec compile("x=x+1", "", "exec")
    print x     # prints 1

f()
g()

I'll leave that one for Guido to rationalize away <wink>!