¿Por qué 'continue `no está permitido en una cláusula` finally' en Python?


El siguiente código genera un error de sintaxis:

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

¿Por qué no se permite una instrucción continue dentro de una cláusula finally?

P.d. Este otro código por otro lado no tiene problemas:

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

Si importa, estoy usando Python 2.6.6.

Author: ElenaT, 2011-11-29

6 answers

El uso de continue en una cláusula final está prohibido porque su interpretación habría sido problemática. ¿Qué harías si la cláusula final fuera ejecutada debido a una excepción?

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

Es posible que tomemos una decisión sobre lo que este código debería hacer, tal vez tragándonos la excepción; pero el buen diseño del lenguaje sugiere lo contrario. Si el código confunde a los lectores o si hay una forma más clara de expresar la lógica deseada (tal vez con try: ... except Exception: pass; continue), entonces hay alguna ventaja de dejar esto como un SyntaxError .

Curiosamente, puede poner un return dentro de una cláusula finally-y se tragará todas las excepciones incluyendo KeyboardInterrupt, SystemExit , y MemoryError. Eso probablemente no es una buena idea tampoco ; -)

 24
Author: Raymond Hettinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-29 19:37:56

La Referencia del Lenguaje Python prohíbe el uso de continue dentro de una cláusula finally. No estoy del todo seguro de por qué. Quizás porque continue dentro de la cláusula try asegura que la finally se ejecuta, y decidir qué debe hacer continue dentro de la cláusula finally es algo ambiguo.

Edit: el comentario de @Mike Christensen a la pregunta señala un hilo donde la ambigüedad de esta construcción es discutida por los desarrolladores del núcleo de Python. Además, en más de nueve años de uso de Python, Nunca he querido hacer esto, así que probablemente sea una situación relativamente poco común en la que los desarrolladores no tengan ganas de pasar mucho tiempo.

 6
Author: Michael Hoffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-28 21:17:57

Creo que la razón de esto es en realidad bastante simple. La instrucción continue después de la palabra clave finally se ejecuta cada vez. Esa es la naturaleza de la declaración final. Si tu código lanza o no una excepción es irrelevante. Finalmente será ejecutado.

Por lo tanto, su código...

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!

Es equivalente a este código...

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

Que es más limpio y conciso. Python no permite continuar en un bloque finally porque todo el código después de continuar nunca será ejecutar. (Disperso es mejor que denso.)

 2
Author: Josh Imhoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-29 02:02:21

No lo vi mencionado en otra respuesta, pero creo que lo que podría querer en este caso es 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

El bloque else solo se ejecuta si no hubo excepción. Lo que esto significa es:

  1. Nosotros print i
  2. Nosotros try a do_something_that_might_fail(i)
  3. Si se lanza SomeException, caer a través y print i de nuevo
  4. De lo contrario, nosotros continue (y i nunca se imprime)
 2
Author: jathanism,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:23:06

La posibilidad de obtener una excepción planteada y luego simplemente tragada porque está utilizando un continue es un argumento fuerte, pero la excepción también se ingiere cuando se utiliza un break o return en su lugar.

Por ejemplo, esto funciona y la excepción es tragada:

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

Esto de nuevo funciona sin error (cuando está en una función) y la excepción también se traga:

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

Entonces, ¿por qué break y return ser permitido en un finally bloque, con o sin posible planteadas errores, pero continue no?

También podría considerar la combinación de los siguientes factores en el asunto:{[26]]}

  • finally siempre se ejecuta;
  • continue "aborta" la iteración actual.

Esto significará que dentro de cada bucle, debido a la finally siempre ejecutándose, siempre tendrá una continue bruja básicamente dice que "abortar iteración actual", "abortar iteración actual", "abortar iteración actual" ... la bruja no tiene ningún sentido. Pero no tiene sentido usar break y return. La iteración actual también se aborta con la única diferencia que ahora terminas con una sola iteración.

Entonces la pregunta "¿Por qué continue no está permitido en un finally?"también se puede preguntar como" ¿Por qué se permite break y return?".

Tal vez porque tenía sentido no hacerlo en ese momento? Fue la decisión de los desarrolladores y ahora es como es? Claro, también podría ser la pereza del implementador, pero quién sabe, tal vez tenían algo en mente y tal vez, en otra versión de Python, haría más ¿sentido de tenerlo de otra manera?

La idea es que los ejemplos aquí son simplemente extremos. No escribes código así, ¿verdad? Hay algunos lógica en el bloque finally para decir cuándo a break/return/continue, lo que sea, y no solo tener que romo así. Como tal, IMHO continue dentro de un finally debería ser permitido porque apreciaría escribir un código limpio con el uso de continue en finally si eso es lo que necesito, en lugar de recurrir a una solución de código para esta limitación (es decir, en la filosofía de Python "Todos somos adultos que consentimos aquí").

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-01 14:11:50

Una declaración continue era ilegal en la cláusula finally debido a un problema con la implementación. En Python 3.8 esta restricción fue levantada.

El error fue issue32489 - Allow 'continue' in 'finally' clause.

La solicitud de extracción para la corrección: https://github.com/serhiy-storchaka/cpython/pull/2

 0
Author: wim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-20 05:32:23