¿Por qué necesitamos la cláusula "finally" en Python?
No estoy seguro de por qué necesitamos {[2] {} en[3]} declaraciones. En mi opinión, este bloque de código
try:
run_code1()
except TypeError:
run_code2()
other_code()
Es lo mismo con este usando finally
:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
¿Me estoy perdiendo algo?
11 answers
Hace una diferencia si regresa temprano:
try:
run_code1()
except TypeError:
run_code2()
return None # The finally block is run before the method returns
finally:
other_code()
Compárese con esto:
try:
run_code1()
except TypeError:
run_code2()
return None
other_code() # This doesn't get run if there's an exception.
Otras situaciones que pueden causar diferencias:
- Si se lanza una excepción dentro del bloque except.
- Si se lanza una excepción en
run_code1()
pero no es unTypeError
. - Otras declaraciones de flujo de control como
continue
ybreak
.
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
2012-07-19 00:01:10
Puede usar finally
para asegurarse de que los archivos o recursos estén cerrados o liberados independientemente de si se produce una excepción, incluso si no se detecta la excepción. (O si no captas esa excepción específica.)
myfile = open("test.txt", "w")
try:
myfile.write("the Answer is: ")
myfile.write(42) # raises TypeError, which will be propagated to caller
finally:
myfile.close() # will be executed before TypeError is propagated
En este ejemplo sería mejor usar la instrucción with
, pero este tipo de estructura se puede usar para otros tipos de recursos.
Unos años más tarde, escribí una entrada de blog sobre un abuso de finally
que los lectores pueden encontrar divertido.
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-28 18:49:37
No son equivalentes. Finalmente el código se ejecuta sin importar qué más suceda. Es útil para el código de limpieza que tiene que ejecutarse.
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
2012-07-18 23:46:12
Los bloques de código no son equivalentes. La cláusula finally
también se ejecutará si run_code1()
lanza una excepción que no sea TypeError
, o si run_code2()
lanza una excepción, mientras que other_code()
en la primera versión no se ejecutaría en estos casos.
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
2012-07-18 23:46:36
En su primer ejemplo, ¿qué sucede si run_code1()
plantea una excepción que no es TypeError
? ... other_code()
no se ejecutará.
Compare eso con la versión finally:
: other_code()
se garantiza que se ejecutará independientemente de cualquier excepción que se genere.
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
2012-07-18 23:47:41
Para agregar a las otras respuestas anteriores, la cláusula finally
se ejecuta sin importar qué mientras que la cláusula else
se ejecuta solo si no se planteó una excepción.
Por ejemplo, escribir en un archivo sin excepciones generará lo siguiente:
file = open('test.txt', 'w')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
SALIDA:
Writing to file.
Write successful.
File closed.
Si hay una excepción, el código generará lo siguiente (tenga en cuenta que un error deliberado es causado por mantener el archivo solo lectura.
file = open('test.txt', 'r')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
SALIDA:
Could not write to file.
File closed.
Podemos ver que la cláusula finally
se ejecuta independientemente de una excepción. Espero que esto ayude.
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-12-13 06:46:06
finally
es para definir "acciones de limpieza". La cláusula finally
se ejecuta en cualquier caso antes de salir de la instrucción try
, ya sea que se haya producido o no una excepción (incluso si no la maneja).
Secundo el ejemplo de @Byers.
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
2015-05-15 17:59:29
Finalmente también se puede usar cuando se desea ejecutar código "opcional" antes de ejecutar el código para su trabajo principal y ese código opcional puede fallar por varias razones.
En el siguiente ejemplo, no sabemos exactamente qué tipo de excepciones store_some_debug_info
podría generar.
Podríamos ejecutar:
try:
store_some_debug_info()
except Exception:
pass
do_something_really_important()
Pero, la mayoría de los linters se quejan de la captura demasiado vaga de una excepción. Además, dado que elegimos solo pass
para errores, el bloque except
realmente no agrega valor.
try:
store_some_debug_info()
finally:
do_something_really_important()
El código anterior tiene el mismo efecto que el 1er bloque de código, pero es más conciso.
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-02-17 17:14:46
El ejemplo perfecto es el siguiente:
try:
#x = Hello + 20
x = 10 + 20
except:
print 'I am in except block'
x = 20 + 30
else:
print 'I am in else block'
x += 1
finally:
print 'Finally x = %s' %(x)
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-10-02 06:33:36
Como se explica en la documentación , la cláusula finally
tiene por objeto definir las acciones de limpieza que deben ejecutarse en todas las circunstancias.
Si
finally
está presente, especifica un controlador 'cleanup'. Eltry
se ejecuta la cláusula, incluyendo las cláusulasexcept
yelse
. Si un excepción se produce en cualquiera de las cláusulas y no se maneja, el la excepción se guarda temporalmente. Se ejecuta la cláusulafinally
. Si hay una excepción guardada que es al final de lafinally
clausula.
Un ejemplo:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
Como puede ver, la cláusula finally
se ejecuta en cualquier caso. La TypeError
elevada dividiendo dos cadenas no es manejada por la cláusula except
y por lo tanto re-elevada después de que la cláusula finally
haya sido ejecutada.
En aplicaciones del mundo real, la cláusula finally es útil para liberar recursos externos (como archivos o conexiones de red), independientemente de si el uso del recurso fue exitoso.
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-12-03 13:20:56
Usar delphi profesionalmente durante algunos años me enseñó a salvaguardar mis rutinas de limpieza usando finalmente. Delphi prácticamente impone el uso de finally para limpiar cualquier recurso creado antes del bloque try, para que no cause una pérdida de memoria. Así también funciona Java, Python y Ruby.
resource = create_resource
try:
use resource
finally:
resource.cleanup
Y el recurso se limpiará independientemente de lo que hagas entre el intento y finalmente. Además, no se limpiará si la ejecución nunca llega al bloque try
. (es decir, create_resource
se lanza una excepción) Hace que su código "excepción segura".
En cuanto a por qué realmente necesita un bloque final, no todos los idiomas lo hacen. En C++, donde ha llamado automáticamente destructores que imponen la limpieza cuando una excepción desenrolla la pila. Creo que este es un paso adelante en la dirección de un código más limpio en comparación con try...finalmente idiomas.
{
type object1;
smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.
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-06-21 21:43:16