utilizar - ¿Por qué `continue` no está permitido en una cláusula` finally` en Python?
traceback(most recent call last) python (6)
Creo que la razón para esto 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, tu 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 terser. 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)
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 declaración de continue
dentro de una cláusula finally
?
PD: 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.
El uso de continuar en una cláusula finally está prohibido porque su interpretación habría 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 debería hacer este código, 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 un SyntaxError .
Curiosamente, puede poner un retorno dentro de una cláusula finally y se tragará todas las excepciones, incluidas KeyboardInterrupt , SystemExit y MemoryError . Probablemente tampoco sea una buena idea ;-)
La posibilidad de obtener una excepción y luego simplemente tragarla porque está utilizando un continue
es un argumento fuerte, pero la excepción también se traga cuando utiliza un break
o return
en return
lugar.
Por ejemplo, esto funciona y se traga la excepción:
for i in range(10):
print i
try:
raise Exception
finally:
break
print i # not gonna happen
De nuevo, esto funciona sin ningún 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é se permitiría el break
y el return
en un bloque finally
, con o sin posibles errores planteados, pero no continue
?
También puede considerar la combinación de los siguientes factores en el problema:
-
finally
siempre se ejecuta; -
continue
"aborta" la iteración actual.
Esto significa que dentro de cada bucle, debido a que finally
siempre se ejecutará, siempre tendrás una palabra de continue
que básicamente dice "abortar la iteración actual", "abortar la iteración actual", "abortar la iteración actual" ... realmente no hace cualquier sentido. Pero tampoco tiene sentido usar break
y return
. La iteración actual también se interrumpe con la única diferencia de que ahora termina con una sola iteración.
Entonces la pregunta "¿Por qué no se permite continue
en un finally
?" también se puede preguntar como "¿Por qué se permiten las break
y el return
?".
Tal vez porque tenía sentido no hacerlo en ese momento? Fue 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, tendría más sentido que fuera de otra manera.
La idea es que los ejemplos aquí son simplemente extremos . No solo escribes código así, ¿verdad? Seguramente habrá algo de lógica en el bloque final para decir cuándo break/return/continue
, lo que sea, y no solo hacerlo de esa manera. Como tal, en mi humilde opinión, finally
debería permitirse escribir un código limpio con el uso de continue
por finally
si eso es lo que necesito, en lugar de recurrir a un código de solución para esta limitación (es decir, en la filosofía de Python "Todos somos consentir adultos aquí ").
No vi que se mencionara 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 ninguna excepción. Entonces, ¿qué significa esto?
- Nosotros
print i
- Tratamos de
do_something_that_might_fail(i)
- Si arroja
SomeException
,SomeException
eSomeException
nuevo - De lo contrario,
continue
(y nunca se imprime)
Python Language Reference prohíbe el uso de continue
en una cláusula finally
. No estoy del todo seguro de por qué. Tal vez porque continue
dentro de la cláusula try
asegura que finally
se ejecuta, y decidir qué continue
debería hacer dentro de la cláusula finally
es algo ambiguo.
Editar: El comentario de @Mike 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.
Una declaración de continuación era ilegal en la cláusula finally debido a un problema con la implementación. En Python 3.8 esta restricción se levantó.
El error fue issue32489 - Permitir ''continuar'' en la cláusula ''finally'' .
La solicitud de extracción para la corrección: https://github.com/serhiy-storchaka/cpython/pull/2