2011-11-28 6 views
36

El siguiente código genera un error de sintaxis:¿Por qué `continue` no está permitido en una cláusula` finally` en Python?

>>> 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 es una declaración continue permitido dentro de una cláusula de finally?

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

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

Si es importante, estoy usando Python 2.6.6.

+2

¿Parece pura vagancia? http://www.gossamer-threads.com/lists/python/dev/484210 –

+0

@Mike Christensen: También encontré ese hilo, pero los documentos dicen "continuar solo puede ocurrir sintácticamente anidado en un bucle for o while, pero no anidado en una definición de función o clase ** o cláusula final dentro de ese bucle ** ". Entonces, ¿era esta pereza o era algo deliberado que más tarde necesitaba un cambio? ... como tantas cosas en Python ... – ElenaT

+0

¿Leíste todo el hilo? - Hay información interesante acerca de lo que realmente significaría 'continuar' en un bloque final, y varios problemas que podrían surgir. Vale la pena leer. –

Respuesta

24

El uso de continuar en una cláusula final está prohibido porque su interpretación hubiera sido problemática. ¿Qué harías si se ejecutara la cláusula finally por 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 tragando la excepción; pero un buen diseño del lenguaje sugiere lo contrario. Si el código confunde a los lectores o si hay una manera más clara de expresar la lógica prevista (quizás con try: ... except Exception: pass; continue), entonces hay alguna ventaja al dejar esto como SyntaxError.

Curiosamente, se puede poner un retorno dentro de una cláusula final y se tendrá que tragar todas las excepciones incluidas KeyboardInterrupt, SystemExit y MemoryError. Probablemente tampoco sea una buena idea ;-)

+4

Estoy de acuerdo. El uso de una cláusula finally es generalmente para atar cabos sueltos si una excepción interrumpió su procedimiento. Para "finalmente continuar" (también sin sentido en inglés) se correría el riesgo de repetir la excepción hasta que termine el bucle, o incluso repetirlo infinitamente, si hubiera un problema que afectara a la condición del bucle. – paislee

+2

Una continuación en un bloque finally podría manejarse de la misma manera que una devolución o un aumento. En este ejemplo, la excepción sería eliminada y el ciclo continuaría. –

+2

Creo que la gente olvida que el código en un bloque 'finally' SIEMPRE SE EJECUTA. – jathanism

6

The Python Language Reference forbids the use of 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 se ejecuta finally, y decidir qué continue debe hacer dentro de la cláusula finally es algo ambiguo.

Editar: @Mike El comentario de Christensen a la pregunta señala un hilo en el que los desarrolladores principales de Python debaten la ambigüedad de esta construcción. Además, en más de nueve años de uso de Python, nunca quise hacer esto, por lo que es probablemente una situación relativamente poco común en la que los desarrolladores no tienen ganas de pasar mucho tiempo.

+0

Parece una buena explicación para mí. La combinación de 'finally' y' continue' es definitivamente algo que valdría la pena refactorizar. – jsalonen

+2

Sí, en estos casos, a veces es mejor no permitir que los desarrolladores hagan algo; de lo contrario, debe especificar, abordar y corregir cualquier rareza que surja de la decisión de permitir tales cosas. –

3

Creo que el motivo es bastante simple. La instrucción continue después de la palabra clave finally se ejecuta todo el tiempo. Esa es la naturaleza de la declaración final. Si su código arroja una excepción o no 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 más concisa. Python no permite continuar en un bloque finally porque todos los códigos posteriores al continuar nunca se ejecutarán. (Sparse es mejor que denso.)

2

Yo no lo vi mencionado en otra respuesta, pero creo que lo que se podría desear 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 sólo se ejecuta si no hay excepción. Lo que esto significa es:

  1. Nos print i
  2. Nos try-do_something_that_might_fail(i)
  3. Si se lanza SomeException, caen a través y print i nuevo
  4. De lo contrario, continue (y i nunca es impresa)
2

La posibilidad de obtener una excepción se elevó y luego se tragó porque Está utilizando un continue es un argumento fuerte, pero la excepción también se traga cuando utiliza un break o return en su lugar.

Por ejemplo, esto funciona y la excepción se ingiere:

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

De nuevo, esto funciona sin error (cuando en una función) y la excepción es tragado demasiado:

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

Entonces, ¿por ¿Se permiten break y return en un bloque finally, con o sin posibles errores elevados, pero continue no?

También puede considerar la combinación de los siguientes factores en la edición:

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

Esto significa que dentro de cada bucle, debido a la ejecución de finally siempre, siempre tendrá una bruja continue básicamente dice "abortar iteración actual", "abortar iteración actual", "abortar iteración actual" .. . bruja realmente no tiene ningún sentido. Pero tampoco tiene sentido usar break y return. La iteración actual también se interrumpe con la única diferencia que ahora termina 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 permiten break y return?".

¿Quizás 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 quizás, en otra versión de Python, sería más sentido tenerlo de otra manera.

La idea es que los ejemplos aquí son simplemente extremos. No solo escribes código así, ¿verdad? Seguramente habrá un poco de lógica en el bloque finally para decir cuándo break/return/continue, lo que sea, y no solo que sea tan contundente. Como tal, se debe permitir IMHO continue dentro de finally porque agradecería escribir un código limpio usando 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 consentir adultos aquí ").

+1

Llego un poco tarde a esta discusión, pero una instrucción 'continue' dentro de una cláusula' finally' no necesariamente significa que se cancelará cada iteración porque puede ajustar la instrucción 'continue' dentro de un condicional. (Que sigue siendo un SyntaxError) – Fraxtil

Cuestiones relacionadas