【问题标题】:Why is `continue` not allowed in a `finally` clause in Python?为什么 Python 的“finally”子句中不允许“continue”?
【发布时间】:2023-04-11 06:06:01
【问题描述】:

以下代码引发语法错误:

>>> for i in range(10):
...     print i
...     try:
...        pass
...     finally:
...        continue
...     print i
...
  File "<stdin>", line 6
SyntaxError: 'continue' not supported inside 'finally' clause

为什么在 finally 子句中不允许使用 continue 语句?

附:另一方面,其他代码没有问题:

>>> for i in range(10):
...     print i
...     try:
...        pass
...     finally:
...        break
...
0

如果重要的话,我使用的是 Python 2.6.6。

【问题讨论】:

  • 看起来只是纯粹的懒惰? gossamer-threads.com/lists/python/dev/484210
  • @Mike Christensen:我也找到了那个线程,但文档说“继续可能只在语法上嵌套在 for 或 while 循环中,但不能嵌套在函数或类定义中 或 finally该循环中的子句”。那么这是懒惰还是故意的,后来需要改变? ... 就像 Python 中的很多东西一样 ...
  • 您阅读了整个主题吗? - 底部有一些有趣的信息,关于在 finally 块中 continue 的实际含义,以及可能出现的各种问题。值得一读。
  • @Mike Christensen:Ups...错过了。确实,对于所描述的情况,这是有道理的。

标签: python syntax-error continue finally


【解决方案1】:

finally 子句中的 Python 语言参考 forbids the use of continue。我不完全确定为什么。可能是因为try 子句中的continue 确保finally 被执行,而决定continuefinally 子句中应该做什么有点模棱两可。

编辑:@Mike Christensen 对该问题的评论指出了 Python 核心开发人员讨论此构造的歧义的线程。此外,在使用 Python 超过 9 年的时间里,我从来没有想过这样做,所以这可能是开发人员不想在上面花费太多时间的相对少见的情况。

【讨论】:

  • 对我来说似乎是一个很好的解释。 finallycontinue 的组合绝对值得重构。
  • 是的,在这些情况下,有时最好不要让开发人员做某事 - 否则您必须规范、解决和修复因决定允许此类事情而产生的任何奇怪问题。
【解决方案2】:

在 finally 子句中使用 continue 是被禁止的,因为它的解释会有问题。如果 finally 子句因为异常而被执行,你会怎么做?

for i in range(10):
    print i
    try:
       raise RuntimeError
    finally:
       continue        # if the loop continues, what would happen to the exception?
    print i

我们可以决定这段代码应该做什么,也许吞下异常;但良好的语言设计表明并非如此。如果代码让读者感到困惑,或者如果有更清晰的方式来表达预期的逻辑(可能使用try: ... except Exception: pass; continue),那么将其保留为 SyntaxError 会有一些好处。

有趣的是,您可以将 return 放在 finally 子句中,它会吞下所有异常,包括 KeyboardInterruptSystemExit内存错误。这可能也不是一个好主意;-)

【讨论】:

  • 我同意。如果异常中断了您的过程,finally 子句的使用通常是为了解决松散的问题。 “finally continue”(在英语中也是无意义的)将冒着重复异常直到循环终止的风险,或者如果存在影响循环条件本身的问题,甚至无限重复它。
  • finally 块中的 continue 可以以与 return 或 raise 相同的方式处理。在此示例中,异常将被吞下,循环将继续。
  • 我认为人们忘记了 finally 块中的代码总是被执行。
【解决方案3】:

我认为原因其实很简单。每次都执行 finally 关键字之后的 continue 语句。这就是 finally 语句的性质。您的代码是否引发异常无关紧要。最后会被执行。

因此,您的代码...

for i in range(10):
   print i
   try:
       pass
   finally:
       continue
   print i # this (and anything else below the continue) won't ever be executed!

等价于这段代码...

for i in range(10:
    print i
    try:
        pass
    finally:
        pass

更简洁。 Python 不允许在 finally 块中继续,因为 continue 之后的所有代码将永远不会被执行。 (稀疏优于密集。)

【讨论】:

    【解决方案4】:

    我没有在另一个回复中看到它,但我认为在这种情况下你可能想要的是try..else

    for i in range(10):
        print i
        try:
           #pass <= I commented this out!
           do_something_that_might_fail(i)
        except SomeException:
           pass
        else:
           continue
        print i
    

    else 块只有在没有异常的情况下才会执行。所以这意味着:

    1. 我们print i
    2. 我们trydo_something_that_might_fail(i)
    3. 如果它抛出SomeException,则再次抛出print i
    4. 否则,我们将continue(并且永远不会打印i

    【讨论】:

      【解决方案5】:

      由于您使用 continue 而引发异常然后被吞掉的可能性是一个强有力的论据,但是当您改用 breakreturn 时,异常也会被吞掉。

      例如,这有效并且异常被吞没:

      for i in range(10):
          print i
          try:
              raise Exception
          finally:
              break
          print i       # not gonna happen
      

      这再次没有错误(在函数中)并且异常也被吞没了:

      for i in range(10):
          print i
          try:
              raise Exception
          finally:
              return
          print i       # not gonna happen
      

      那么为什么breakreturn 允许在finally 块中,无论是否可能引发错误,但continue 不允许?

      您还可以考虑以下因素的组合问题:

      • finally 总是被执行;
      • continue“中止”当前迭代。

      这意味着在每个循环中,由于finally 总是在执行,所以基本上你总是有一个continue 女巫 说“中止当前迭代”,“中止当前迭代”,“中止当前迭代”......女巫真的没有任何意义。但是使用breakreturn 也没有任何意义。当前迭代也被中止,唯一的区别是 你现在只需要一次迭代。

      所以问题是“为什么 continue 不允许出现在 finally 中?”也可以问为“为什么允许breakreturn?”。

      也许是因为那时不这样做是有道理的? 这是开发人员的决定,现在还是这样?当然,这也可能是实施者的懒惰,但谁知道呢,也许他们有什么想法,也许在另一个版本的 Python 中,它会做更多 换一种方式有意义吗?

      想法是这里的例子只是极端的。你不只是写那样的代码,对吗?肯定会有一些 finally 块中的逻辑来说明何时到break/return/continue,无论如何,而不是像那样直言不讳。因此,恕我直言,finally 内的 continue 应该被允许,因为如果这是我需要的,我将不胜感激在 finally 中使用 continue 编写干净的代码,而不是诉诸代码解决方法来解决这个限制(即在 Python 的哲学“我们都是同意的成年人”)。

      【讨论】:

      • 我对这个讨论有点晚了,但是 finally 子句中的 continue 语句并不一定意味着每次迭代都会中止,因为您可以包装 continue 语句条件句内。 (这仍然是一个 SyntaxError。)
      【解决方案6】:

      由于实现存在问题,finally 子句中的 continue 语句是非法的。在 Python 3.8 中,这个限制被取消了。

      错误是issue32489 - Allow 'continue' in 'finally' clause

      修复的拉取请求:https://github.com/python/cpython/pull/5822

      【讨论】:

        【解决方案7】:

        现在这个功能在 3.8 版本中可用

        https://docs.python.org/3/whatsnew/3.8.html

        示例代码

        def new_f():
            for i in range(0,24):
                try:
                    print(1/0)
                except:
                    print('In Exception')
                finally:
                    print('In finally')
                    continue
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-07-18
          • 2011-01-21
          • 2012-05-19
          • 1970-01-01
          • 2017-07-17
          • 1970-01-01
          • 2012-08-31
          相关资源
          最近更新 更多