Behavior of exec function in Python 2 and Python 3
Question: Following code gives different output in `Python2` and in `Python3`:

    
    
    from sys import version
    
    print(version)
    
    def execute(a, st):
        b = 42
        exec("b = {}\nprint('b:', b)".format(st))
        print(b)
    a = 1.
    execute(a, "1.E6*a")
    

`Python2` prints:

    
    
    2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]
    ('b:', 1000000.0)
    1000000.0
    

`Python3` prints:

    
    
    3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
    b: 1000000.0
    42
    

Why does `Python2` bind the variable `b` inside the `execute` function to the
values in the string of the `exec` function, while `Python3` doesn't do this?
How can I achieve the behavior of `Python2` in `Python3`? I already tried to
pass dictionaries for globals and locals to `exec` function in `Python3`, but
nothing worked so far.

**\--- EDIT ---**

After reading Martijns answer I further analyzed this with `Python3`. In
following example I give the `locals()` dictionay as `d` to `exec`, but
`d['b']` prints something else than just printing `b`.

    
    
    from sys import version
    
    print(version)
    
    def execute(a, st):
        b = 42
        d = locals()
        exec("b = {}\nprint('b:', b)".format(st), globals(), d)
        print(b)                     # This prints 42
        print(d['b'])                # This prints 1000000.0
        print(id(d) == id(locals())) # This prints True
    a = 1.
    execute(a, "1.E6*a")
    
    3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
    b: 1000000.0
    42
    1000000.0
    True
    

The comparison of the ids of `d` and `locals()` shows that they are the same
object. But under these conditions `b` should be the same as `d['b']`. What is
wrong in my example?


Answer: There is a big difference between `exec` in Python 2 and `exec()` in Python 3.
You are treating `exec` as a function, but it really is a _statement_ in
Python 2.

Because of this difference, you cannot change local variables in function
scope in Python 3 using `exec`, even though it was possible in Python 2. Not
even previously declared variables.

`locals()` only reflects local variables in one direction. The following never
worked in either 2 or 3:

    
    
    def foo():
        a = 'spam'
        locals()['a'] = 'ham'
        print(a)              # prints 'spam'
    

In Python 2, using the `exec` statement meant the compiler knew to switch off
the local scope optimizations (switching from `LOAD_FAST` to `LOAD_NAME` for
example, to look up variables in both the local and global scopes). With
`exec()` being a function, that option is no longer available and function
scopes are now _always_ optimized.

Moreover, in Python 2, the `exec` statement explicitly copies all variables
found in `locals()` back to the function locals using `PyFrame_LocalsToFast`,
but only if no _globals_ and _locals_ parameters were supplied.

The proper work-around is to use a new namespace (a dictionary) for your
`exec()` call:

    
    
    def execute(a, st):
        namespace = {}
        exec("b = {}\nprint('b:', b)".format(st), namespace)
        print(namespace['b'])
    

