【问题标题】:Why does Python's CONTINUE_LOOP allow an outer loop, when BREAK_LOOP doesn't?为什么 Python CONTINUE LOOP 允许外部循环,而 BREAK LOOP 不允许?
【发布时间】:2017-06-06 08:16:37
【问题描述】:

我注意到 Python 的字节码 here 中有一个有趣的特性。

CONTINUE_LOOP 操作码接受一个target 参数,该参数表示循环继续执行的指令,即FOR_ITER 指令。

但是,BREAK_LOOP 操作码不这样做。它只会跳出当前(最里面的)循环。

这背后的原因是什么?为什么可以continue 而不是break 外循环?

【问题讨论】:

  • 这样的不一致大部分是由于代码的演变造成的。但这只是我的猜测。

标签: python loops bytecode cpython python-internals


【解决方案1】:

你误解了目标。处理嵌套循环不需要该值。相反,目标标记字节码流中要在指令之后移动到的点。 BREAK 不需要这样的目标,因为该值已在别处定义。

BREAK_LOOP 结束一个循环,因此在循环之后继续执行。 SETUP_LOOP instruction 已经定义了端点,所以解释器不需要任何额外的信息来执行这个操作码。

另一方面,CONTINUE_LOOP 需要被告知在哪里继续。在大多数循环中,使用JUMP_ABSOLUTE opcodeCONTINUE_LOOP 在此处回显该指令。 CONTINUE_LOOP 记录了更多信息以处理 try 语句(跟踪堆栈展开)。

在评估循环中,异常处理(try: ... except:try : ... finally:)以及上下文管理器(with ...:async with ...:)使用 帧块 的通用概念,它为它记录了一个退出点,这是 BREAK_LOOP 指令在这里所依赖的。这种方式不必跟踪偏移量更简单,并且避免了编译器和评估循环不得不重复自己(退出点也用于其他场景,而不仅仅是break 语句)。

但是跳转更通用,因此它们的偏移量更容易与指令本身相关联。

【讨论】:

  • 一时觉得自己明白了,但现在又觉得自己不太明白。 CONTINUE_LOOP 只能跳转到一个位置:第一个循环指令。如果SETUP_LOOP 已经指定了循环的位置,那么解释器不知道如何重新输入它,就像它知道如何退出它一样?毕竟,它已经被告知循环范围,对吧?
  • @Mehrdad:您需要将跳转目标存储在某处JUMP_ABSOLUTECONTINUE_LOOP 将其存储为操作码的偏移量。这比让评估循环一直跟踪所有可能的循环相关值更容易管理。
  • @MartijnPieters:我的意思是那为什么这个论点不能同样适用于BREAK_LOOP?如果它就在那里而不是解释器必须跟踪它,是否更容易管理?
  • @Mehrdad:循环、exceptfinally 块的处理方式相同,因此它们的帧块对象已被概括;他们都使用退出偏移量。使用此设置简化了评估循环代码。
  • @Mehrdad:(当使用列表解析时,FOR_ITER 可以出现没有SETUP_LOOP,这并不重要)。
猜你喜欢
  • 2013-03-13
  • 2023-04-11
  • 2020-06-02
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
相关资源
最近更新 更多