为什么 exec("break") 在 while 循环中不工作

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

正如问题所问,为什么下面的代码不起作用:

while True:
      exec("break")

我正在通过 python 3.5.2 控制台在 pycharm 中执行上述操作。 我最初认为这是一个上下文问题,但在阅读文档后,我还没有进一步理解为什么会出现此错误。

SyntaxError: 'break' outside loop

提前致谢:)

编辑: 我知道它可以在没有 exec() 的情况下工作,我很好奇为什么它不能与 exec 一起工作(因为我的情况需要它) -欢迎全面回答。

尝试不使用 exec() 中断:

while True:
  break

这是因为 exec() 不知道您周围的 while 循环。因此,exec() 在您的示例中看到的唯一语句是 break。不要使用 exec("break"),只需按原样使用 break

exec() 函数对其周围范围的唯一访问权限是 globals()locals() 字典。 The documentation for exec() 提供了一些关于 exec() 工作原理的见解:

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().

exec 语句 运行 是独立于其余代码的一小段代码。

因此,行:

exec("break")

等同于在脚本中无处不在地调用 break,其中没有其他任何事情发生,并且不存在循环。

调用break语句的正确方法是:

while True:
    break

编辑

Leaf的评论让我想到了。

实际上,exec 语句不会 运行 代码无处不在。

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

据我所知,更好的答案是 exec 运行 是与原始代码在相同 环境 中的一段代码,但独立于它。

这基本上意味着在exec调用的那一刻存在的所有变量都可以在exec调用的代码中使用。但是上下文是全新的,因此 returnbreakcontinue 和其他需要上下文的语句将不起作用,除非创建了正确的上下文。

顺便说一句,我在谈论exec时保留了"statement"这个词,但它在Python3中变成了一个函数,print也是如此。

exec 是内置函数,

Python 坚持认为 break 应该发生在循环内,而不是在 function

您的代码中发生的事情是您将 break 放入 function 中,即 exec 您无法通过执行 break 在循环内调用的函数内。

前者

>>> def func():
        break
SyntaxError: 'break' outside loop
>>> 

exec() 是一个函数。为简单起见,假设函数调用构成了自​​己的语句(就像在您的示例中一样),它可能以下列方式之一结束:

  1. 函数returns正常-在这种情况下,根据控制流执行下一条语句;

  2. 异常是 raised/thrown 来自函数 - 在这种情况下,执行调用堆栈(如果有)上的匹配 except 子句

  3. 整个程序因显式调用 exit() 或等效函数而终止 - 没有可执行的内容。

exec() 内部调用 break(以及 returnyield)会以与描述的不兼容的方式修改程序执行流程函数调用语义的方面。

请注意,the documentation on exec() 包含关于在 exec() 中使用 returnyield 的特别说明:

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.

类似的限制适用于break语句(区别在于它不能在loops之外使用),我想知道为什么它没有包含在文档。

exec 函数在代码中运行代码,这意味着它无处不在!所以,你的 while 循环没有捕捉到它。您的文件是 <stdin>exec 在另一个名为 <string> 的文件上运行。它无法识别您试图在没有循环的地方打破循环的地方。所以,你的代码是这样的:

while True:
    exec("break")

应该是这样的:

while True:
    break