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'])

The exec() documentation is very explicit about this limitation:

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

Answer from Martijn Pieters on Stack Overflow
๐ŸŒ
DataFlair
data-flair.training โ€บ blogs โ€บ python-exec-function
Python exec Function - Example and Risk - DataFlair
November 24, 2018 - 2. How do you pass arguments to exec in Python? 3. What is the difference between eval and exec in Python? 4. What is the use of exec in Python? 5. How does exec work in Python? Hence, in this Python exec tutorial, we will say that exec supports the dynamic execution of Python code.
๐ŸŒ
Programiz
programiz.com โ€บ python-programming โ€บ methods โ€บ built-in โ€บ exec
Python exec() (With Examples)
The method executes the python code inside the object method and produces the output Sum = 15. # get an entire program as input program = input('Enter a program:') # execute the program exec(program) Output ยท Enter a program: [print(item) for item in [1, 2, 3]] 1 2 3 ยท
Discussions

Behavior of exec function in Python 2 and Python 3 - Stack Overflow
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. More on stackoverflow.com
๐ŸŒ stackoverflow.com
How can I use exec in functions in python3.6 similar to python2.7?
Hello, in python 2.7 the following ... a= 1 in python3.6 this works in the interpreter: b=1 exec(โ€˜a=%sโ€™%b) a 1 but not in a function: def f( b ): โ€ฆ exec( โ€˜a=%sโ€™%b ) โ€ฆ print( โ€˜a=โ€™, a ) โ€ฆ f( 1 ) Traceback (most recent call last): File โ€œโ€, line 1, in File โ€œโ€, line 3, in f NameError: ... More on discuss.python.org
๐ŸŒ discuss.python.org
0
0
August 17, 2021
Using a function defined in an exec'ed string in Python 3 - Stack Overflow
Another interesting question: what are you trying to accomplish with exec, and what's the more-natural Python way to do it? ... Loads of precedent to answer your question; Why did Python 3 changes to exec break this code? More on stackoverflow.com
๐ŸŒ stackoverflow.com
Why is it advised to not use exec?
If you're thinking about using exec, there are two likely scenarios: 1 - you want to execute some code from a string 2 - you want to let users execute code from an input string In option 1, you are already in control of your code, and there are smarter / saner ways of controlling the code flow / logic than using exec. In option 2, there are security concerns because the user can input bad code and brick their system (or your server, if it's an web app). Consider for example: s = input("write your code:") result = exec(s) print(result) If the user inputs import shutil; shutil.rmtree("/"), say goodbye to your filesystem. More on reddit.com
๐ŸŒ r/learnpython
23
23
June 5, 2022
๐ŸŒ
Python documentation
docs.python.org โ€บ 3 โ€บ library โ€บ functions.html
Built-in Functions โ€” Python 3.14.4 documentation
February 27, 2026 - The default locals act as described for function locals() below. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns. Changed in version 3.11: Added the closure parameter.
Top answer
1 of 4
56

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'])

The exec() documentation is very explicit about this limitation:

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

2 of 4
9

I'd say it's a bug of python3.

def u():
    exec("a=2")
    print(locals()['a'])
u()

prints "2".

def u():
    exec("a=2")
    a=2
    print(a)
u()

prints "2".

But

def u():
    exec("a=2")
    print(locals()['a'])
    a=2
u()

fails with

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in u
KeyError: 'a'

--- EDIT --- Another interesting behaviour:

def u():
    a=1
    l=locals()
    exec("a=2")
    print(l)
u()
def u():
    a=1
    l=locals()
    exec("a=2")
    locals()
    print(l)
u()

outputs

{'l': {...}, 'a': 2}
{'l': {...}, 'a': 1}

And also

def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
u()
def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
    a=1
u()

outputs

{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}}

Apparently, the action of exec on locals is the following:

  • If a variable is set within exec and this variable was a local variable, then exec modifies the internal dictionary (the one returned by locals()) and does not return it to its original state. A call to locals() updates the dictionary (as documented in section 2 of python documentation), and the value set within exec is forgotten. The need of calling locals() to update the dictionary is not a bug of python3, because it is documented, but it is not intuitive. Moreover, the fact that modifications of locals within exec don't change the locals of the function is a documented difference with python2 (the documentation says "Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns"), and I prefer the behaviour of python2.
  • If a variable is set within exec and this variable did not exist before, then exec modifies the internal dictionary unless the variable is set afterwards. It seems that there is a bug in the way locals() updates the dictionary ; this bug gives access to the value set within exec by calling locals() after exec.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ exec-in-python
exec() in Python - GeeksforGeeks
November 29, 2023 - Dynamic execution in Python allows the execution of specific methods such as sum() and iter() along with built-in methods inside the exec() function, demonstrating the flexibility of dynamic execution in Python. Through this, only the sum, and iter methods along with all the built-in methods can be executed inside exec() function.
๐ŸŒ
W3Schools
w3schools.com โ€บ python โ€บ ref_func_exec.asp
Python exec() Function
Python Examples Python Compiler ... Python Interview Q&A Python Bootcamp Python Training ... The exec() function executes the specified Python code....
๐ŸŒ
Armin Ronacher
lucumr.pocoo.org โ€บ 2011 โ€บ 2 โ€บ 1 โ€บ exec-in-python
Be careful with exec and eval in Python | Armin Ronacher's Thoughts and Writings
February 1, 2011 - Now how much faster is executing bytecode over creating bytecode and executing that?: $ python -mtimeit -s 'code = "a = 2; b = 3; c = a * b"' 'exec code' 10000 loops, best of 3: 22.7 usec per loop $ python -mtimeit -s 'code = compile("a = 2; b = 3; c = a * b", "<string>", "exec")' 'exec code' 1000000 loops, best of 3: 0.765 usec per loop
Find elsewhere
๐ŸŒ
Vultr Docs
docs.vultr.com โ€บ python โ€บ built-in โ€บ exec
Python exec() - Execute Dynamically | Vultr Docs
September 27, 2024 - Execute the code using exec() while defining the variable externally. ... This snippet defines a Python code in the form of a string that calculates the sum of two variables a and b. It then uses exec() to execute this code, passing a dictionary ...
๐ŸŒ
Codecademy
codecademy.com โ€บ docs โ€บ python โ€บ built-in functions โ€บ exec()
Python | Built-in Functions | exec() | Codecademy
August 24, 2023 - This example uses exec() to parse and execute Python code contained in the string code: ... Hello, Codecademy! ... This example uses exec() to execute Python code from a file code.txt, which contains Python commands:
๐ŸŒ
Quora
quora.com โ€บ In-Python-3-what-are-exec-and-eval-and-how-do-you-use-them
In Python 3, what are exec and eval and how do you use them? - Quora
Answer (1 of 2): They are built-in functions which execute and evaluate strings containing python code respectively. Essentially they are built-in Python self-interpreters. For instance.
๐ŸŒ
w3resource
w3resource.com โ€บ python โ€บ built-in-function โ€บ exec.php
Python exec() function - w3resource
The exec() function is used to execute the specified Python code. object must be either a string or a code object. Version: (Python 3) Syntax: exec(object[, globals[, locals]]) Parameter: Example-1: Python exec() function ยท x = 5 print(exec('x')) ...
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
How can I use exec in functions in python3.6 similar to python2.7? - Python Help - Discussions on Python.org
August 17, 2021 - Hello, in python 2.7 the following ... a= 1 in python3.6 this works in the interpreter: b=1 exec(โ€˜a=%sโ€™%b) a 1 but not in a function: def f( b ): โ€ฆ exec( โ€˜a=%sโ€™%b ) โ€ฆ print( โ€˜a=โ€™, a ) โ€ฆ f( 1 ) Traceback (most recent call last): File โ€œโ€, line 1, in File โ€œโ€, line 3, in f NameError: ...
๐ŸŒ
Real Python
realpython.com โ€บ python-exec
Python's exec(): Execute Dynamically Generated Code โ€“ Real Python
November 10, 2022 - In this tutorial, you'll learn how to use Python's built-in exec() function to execute code that comes as either a string or a compiled code object.
Top answer
1 of 3
29

Note: exec was just a Simple statement in Python 2.x, whereas it is a function in Python 3.x.

Python 2.7

Let us check the changes made by executing a.

class Test:
    def __init__(self):
        l, g = locals().copy(), globals().copy()
        exec a           # NOT a function call but a statement
        print locals() == l, globals() == g
        x()

t = Test()

Output

False True
42

It means that, it has changed something in the locals dictionary. If you print locals().keys() before and after the exec, you will see x, after exec. As per the documentation of exec,

In all cases, if the optional parts are omitted, the code is executed in the current scope.

So, it does exactly what the documentation says.

Python 3.x:

When we execute the same in Python 3.x, we get similar result, except we get that error.

class Test:
    def __init__(self):
        l, g = locals().copy(), globals().copy()
        exec(a)          # Function call, NOT a statement
        print(locals() == l, globals() == g)
        x()

Output

False True
NameError: name 'x' is not defined

Even the documentation of exec function says,

In all cases, if the optional parts are omitted, the code is executed in the current scope.

But it also includes a note at the bottom,

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

So, we curiously check the locals() documentation and find

Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

So, interpreter doesn't honor the changes made to the locals() object. That is why it is not recognizing x as defined in the local scope.

But when we do

def __init__(self):
    exec(a, globals())
    x()

it works, because we add it to the globals dictionary. Python tries to find x in local scope first and then in class scope and then in global scope and it finds it there. So it executes it without any problem.

Using exec(f, globals()) from a function (2.x and 3.x python compatible)

NOTE: If you don't like to pass globals() every time you can refactor you code by wrapping `exec(a, globals())` into a function and using it across modules, but it will require some additional coding, because globals() is per-module and you need those globals() which are from the calling module:

# macros.py
import sys
def execfunc(func_as_str):
    print("(debug) calling module: %s" % sys._getframe(1).f_code.co_filename)
    # See https://github.com/python/cpython/blob/main/Lib/traceback.py
    exec(func_as_str, sys._getframe(1).f_globals)

# main script
import macros
macros.execfunc("def foo(x):\n    print(x)")
foo('bar')
2 of 3
15

Python3 exec also takes globals and locals optional arguments of mapping type, which act as a context for the given code execution:

exec(object[, globals[, locals]])

By default the local scope gets passed in for both. The executed code can use it, can also modify the dict, but it will have no effect on the actual local scope. See locals() and example:

a = '''
print(t)

def x():
    print(42)
'''

class Test:
    def __init__(self):
        t = 'locals are accessible'
        # same as calling exec(a, locals())
        exec(a)
        print(locals())
        x()

t = Test()

Output:

locals are accessible
{'x': <function x at 0x6ffffd09af0>,
'self': <__main__.Test object at 0x6ffffce3f90>,
't': 'locals are accessible'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 13, in __init__
NameError: global name 'x' is not defined

If you want the x to be available after the exec call you either need to pass in a global or a custom scope:

# global scope
class Test:
    def __init__(self):
        exec(a, globals())
        x()

# custom scope
class Test:
    def __init__(self):
        scope = {}
        exec(a, scope)
        scope['x']()
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ why is it advised to not use exec?
r/learnpython on Reddit: Why is it advised to not use exec?
June 5, 2022 -

I asked a question a few days ago on stack overflow about doing exec("func = lambda x:x**2") (or dynamically generating other functions for that matter) and someone said that I should not use exec in my code and instead create a function with def that returns a lambda function.

And it's something that I see in quite a few forums.

๐ŸŒ
Readthedocs
portingguide.readthedocs.io โ€บ en โ€บ latest โ€บ builtins.html
Built-In Function Changes โ€” Conservative Python 3 Porting Guide 1.0 documentation
exec(some_code) exec(some_code, globals) exec(some_code, globals, locals) In Python 2, the syntax was extended so the first expression may be a 2- or 3-tuple.
๐ŸŒ
Real Python
realpython.com โ€บ ref โ€บ builtin-functions โ€บ exec
exec() | Pythonโ€™s Built-in Functions โ€“ Real Python
This function is powerful as it can execute full Python programs, but it should be used with caution due to potential security risks: ... The exec() function returns None as its purpose is to execute code with potential side effects rather than produce a direct result. ... >>> string_input = """ ... def sum_of_even_squares(numbers): ... return sum(number**2 for number in numbers if number % 2 == 0) ... ... print(sum_of_even_squares(numbers)) ... """ >>> numbers = [2, 3, 7, 4, 8] >>> exec(string_input) 84
๐ŸŒ
TutorialsPoint
tutorialspoint.com โ€บ exec-in-python
exec() in Python
Exec function can dynamically execute code of python programs. The code can be passed in as string or object code to this function. The object code is executed as is while the string is first parsed and checked for any syntax error. If no syntax e
๐ŸŒ
AskPython
askpython.com โ€บ home โ€บ understanding the python exec() method
Understanding the Python exec() Method - AskPython
August 6, 2022 - Basically, the Python exec() method executes the passed set of code in the form of string. It is very useful as it practically supports dynamic execution.