【问题标题】:Why doesn't exec("break") work inside a while loop为什么 exec("break") 不能在 while 循环中工作
【发布时间】:2017-03-29 10:57:22
【问题描述】:

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

while True:
      exec("break")

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

SyntaxError: 'break' outside loop

提前致谢:)

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

【问题讨论】:

  • exec 是一个函数,break 应该直接在循环内。

标签: python while-loop exec


【解决方案1】:

在没有 exec() 的情况下尝试 break:

while True:
  break

【讨论】:

  • OP 说他需要知道原因。你的回答没有解释它。
  • @leaf 好吧,我知道他不能发表评论,但这是一个质量非常低的答案。
【解决方案2】:

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

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

此函数支持 Python 代码的动态执行。 object 必须是字符串或代码对象。如果它是一个字符串,则该字符串被解析为一组 Python 语句,然后执行(除非出现语法错误)。 [1] 如果是代码对象,则简单地执行。在所有情况下,执行的代码都应作为文件输入有效(请参阅参考手册中的“文件输入”部分)。请注意,即使在传递给 exec() 函数的代码上下文中,也不能在函数定义之外使用 return 和 yield 语句。返回值为无。

在所有情况下,如果省略可选部分,代码将在当前范围内执行。如果只提供全局变量,它必须是一个字典,它将用于全局变量和局部变量。如果给出了全局变量和局部变量,则它们分别用于全局变量和局部变量。如果提供,locals 可以是任何映射对象。请记住,在模块级别,全局变量和局部变量是同一个字典。如果 exec 获得两个单独的对象作为全局对象和局部对象,则代码将像嵌入到类定义中一样被执行。

如果全局字典不包含键 builtins 的值,则在该键下插入对内置模块 builtins 字典的引用。这样,您可以通过将自己的 builtins 字典插入到全局变量中,然后再将其传递给 exec() 来控制执行代码可用的内置函数。

【讨论】:

  • 所以这是一个上下文问题?有没有办法在当前命名空间/上下文中使用 exec 执行?
  • @Sighonide 据我所知,没有。 exec() 只能访问全局变量,不能访问语句。我可以问你为什么需要这个吗?
  • 那很不幸哈哈。我打算用它来将字符串格式的命令传递给另一个进程,这将在那个进程中操纵一个循环和其他东西。
  • @Sighonide 是的,恐怕是这样。不过,如果你仍然好奇,you can look over the official documentation for exec()
  • 是的,这就是我读到的,不过谢谢 :) 当我看到对本地的引用时我很兴奋,但不幸的是这不是我想要的。
【解决方案3】:

exec 语句独立于其余代码运行一些代码。

因此,行:

exec("break")

相当于在没有其他任何事情发生且不存在循环的脚本中突然调用break

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

while True:
    break

编辑

Leaf 的评论让我想起来了。

实际上,exec 语句不会突然运行代码。

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

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

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

顺便说一句,我在谈到exec时保留了“声明”这个词,但它已经成为Python3中的一个函数,就像print一样。

【讨论】:

  • @leaf 感谢您的思考 ;)
【解决方案4】:

exec 是一个内置函数,

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

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

前任

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

【讨论】:

    【解决方案5】:

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

    1. 函数正常返回——此时根据控制流执行下一条语句;

    2. 函数引发/抛出异常 - 在这种情况下,调用堆栈(如果有)上匹配的 except 子句被执行

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

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

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

    请注意,returnyield 语句不得在外部使用 即使在传递给 exec() 函数。

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

    【讨论】:

    • 是的,break 也应该直接在循环内,而不是像 exec 这样的函数内
    【解决方案6】:

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

    while True:
        exec("break")
    

    应该是这样的:

    while True:
        break
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 1970-01-01
      相关资源
      最近更新 更多