Why doesn't exec("break") work inside a while loop

This is because exec() is ignorant to your surrounding while loop. So the only statement that exec() sees in your example is break. Instead of using exec("break"), simply use break as is.

The only access the exec() function has to its surrounding scope, is the globals() and locals() dictionaries. The documentation for exec() provides some insight into how exec() works:

This function supports dynamic execution of Python code. object must be either a string or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error occurs). [1] If it is a code object, it is simply executed. In all cases, the code that’s executed is expected to be valid as file input (see the section “File input” in the Reference Manual). Be aware that the return and yield statements may not be used outside of function definitions even within the context of code passed to the exec() function. The return value is None.

In all cases, if the optional parts are omitted, the code is executed in the current scope. If only globals is provided, it must be a dictionary, which will be used for both the global and the local variables. If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

If the globals dictionary does not contain a value for the key builtins, a reference to the dictionary of the built-in module builtins is inserted under that key. That way you can control what builtins are available to the executed code by inserting your own builtins dictionary into globals before passing it to exec().


The exec statement runs a bit of code independently from the rest of your code.

Hence, the line:

exec("break")

is tantamount to calling break out of nowhere, in a script where nothing else happens, and where no loop exists.

The right way to call the break statement is:

while True:
    break

EDIT

The comment from Leaf made me think about it.

Actually, the exec statement does not run the code out of nowhere.

>>> i = 12
>>> exec("print(i)")
12

A better answer, as far as I understand, is that exec runs a piece of code in the same environment as the original code, but independently from it.

This basically means that all the variables that exist at the moment exec is called can be used in the code called by exec. But the context is all new, so return, break, continue and other statements that need a context, will not work, unless the right context is created.

By the way, I kept the word "statement" when talking about exec, but it has become a function in Python3, the same way print did.


exec() is a function. Assuming for simplicity that a function call constitutes a statement of its own (just like in your example), it may end in one of the following ways:

  1. the function returns normally - in this case the next statement according to the control flow is executed;

  2. an exception is raised/thrown from the function - in this case the matching except clause on the call stack (if any) is executed

  3. the entire program is terminated due to an explicit call to exit() or equivalent - there is nothing to execute.

Calling a break (as well as return or yield) from inside exec() would modify the program execution flow in a way that is incompatible with the described aspect of the function call semantics.

Note that the documentation on exec() contains a special note on the use of return and yield inside exec():

Be aware that the return and yield statements may not be used outside of function definitions even within the context of code passed to the exec() function.

A similar restriction applies to the break statement (with the difference that it may not be used outside loops), and I wonder why it was not included in the documentation.