Salir/Terminar scripts en Python (Ejemplos simples)
Hoy, nos sumergiremos en el tema de la salida/terminar de los script de Python! Antes de empezar, deberías tener un conocimiento básico sobre su uso.
Puedes usar el IDE que quieras, pero esta vez usaré el paquete Microsoft’s Linux Subsystem for Windows (WSL). Para más información sobre eso y cómo habilitarlo en Windows 10 ve aquí.
Tabla de contenidos
Por que Python sale automaticamente cuando termina un script?
La forma en que Python ejecuta un bloque de código hace que ejecute cada línea en orden, comprobando las dependencias a importar, leyendo definiciones y clases para almacenarlas en la memoria, y ejecutando trozos de código en orden permitiendo bucles y llamadas de vuelta a las definiciones y clases definidas.
Cuando el intérprete de Python llega al final del archivo (EOF), se da cuenta de que no puede leer más datos de la fuente, ya sea la entrada del usuario a través de un IDE o la lectura de un archivo. ¡Para demostrarlo, intentemos obtener la entrada del usuario e interrumpir el intérprete en medio de la ejecución!
Primero, desde tu terminal bash en tu PowerShell abre un nuevo archivo llamado “input.py”:
$ nano input.py
Luego pegue lo siguiente en el shell haciendo clic derecho en la ventana de PowerShell
name=input("Don't type anything!\n") print("Hi,",name,"!")
Ahora, presiona CTRL+X para guardar y salir de la ventana nano y en tu tipo de shell:
$ python3 input.py Don't type anything!
Y presiona CTRL+D para terminar el programa mientras espera la entrada del usuario
Traceback (most recent call last): File "input.py", line 1, in name=input("Don't type anything!") EOFError
La excepción EOFError nos dice que el intérprete de Python alcanzó la condición de fin de archivo (EOF) antes de terminar de ejecutar el código, ya que el usuario no introdujo ningún dato de entrada.
Cuando Python alcanza la condición EOF al mismo tiempo que ha ejecutado todo el código sin lanzar ninguna excepción, que es una forma en que Python puede salir “elegantemente”.”
Detectar la salida del script
Si queremos saber cuándo sale un programa Python sin lanzar una excepción, podemos usar el módulo atexit de Python incorporado.
El atexit maneja cualquier cosa que queramos que haga el programa cuando salga y se usa típicamente para hacer la limpieza del programa antes de que el proceso del programa termine
Para experimentar con atexit, modificamos nuestro ejemplo de input.py para imprimir un mensaje a la salida del programa. Abrir el archivo input.py de nuevo y reemplazar el texto con esto
import atexit atexit.register(print,"Program exited successfully!") name=input("What's your name?\n") print("Hi,",name,"!")
Escriba su nombre, y cuando pulse enter debería obtener:
What's your name? Example Hi, Example ! Program exited successfully!
Fíjate en cómo el texto de salida aparece al final de la salida sin importar dónde colocamos la llamada atexit, y cómo si reemplazamos la llamada atexit por una simple print(), obtenemos el texto de salida donde se hizo la print() todo, en lugar de donde sale el código.
Program exited successfully! What's your name? Example Hi, Example !
Salida elegante
Hay varias maneras de salir de un Programa Python que no implica lanzar una excepción; la primera que vamos a probar es quit().
¿Puedes usar el comando bash echo $? para obtener el código de salida del intérprete de Python.
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> quit() $ echo $? 0
También podemos definir el tipo de código con el que el intérprete debe salir, dando a quit() un argumento entero inferior a 256
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> quit(101) $ echo $? 101
exit()
tiene la misma funcionalidad ya que es un alias para quit()
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> exit(101) $ echo $? 101
Ni quit() ni exit() se consideran buenas prácticas, ya que ambas requieren el modulo del sitio, que está destinado a ser utilizado para los intérpretes interactivos y no en los programas. Para nuestros programas, deberíamos usar algo como sys.exit
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.exit(101) $ echo $? 101
Fíjate que necesitamos importar explícitamente un módulo para llamar a exit(), esto puede parecer que no es una mejora, pero garantiza que el módulo necesario se cargue porque no es un buen sitio de suposición se cargará en tiempo de ejecución.
Si no queremos importar módulos extra, podemos hacer lo que exit(), quit() y sys.exit() están haciendo entre bastidores y levantar SystemExit
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> raise SystemExit(101) $ echo $? 101
Salir con errores de mensajes
¿Qué pasa si recibimos una mala entrada de un usuario? Veamos nuestro script input.py, y agreguemos la habilidad de manejar las malas entradas del usuario (CTRL+D para pasar un caracter EOF)
$ nano input.py try: name=input("What's your name?\n") print("Hi, "+name+"!") except EOFError: print("EOFError: You didn't enter anything!") $ python3 input.py What's your name? EOFError: You didn't enter anything!
La declaración try le dice a Python que pruebe el código dentro de la declaración y que pase cualquier excepción a la declaración except antes de salir.
Salir sin error
¿Qué pasa si el usuario le da un error a su programa, pero usted no quiere que su código imprima un error, o que haga algún tipo de manejo de errores para minimizar el impacto en el usuario?
Podemos añadir una última declaración que nos permite ejecutar el código después de hacer nuestro manejo de errores en la captura.
$ nano input.py try: name=input("What's your name?\n") if(name==''): print("Name cannot be blank!") except EOFError: #print("EOFError: You didn't enter anything!") name="Blankname" finallmente: print("Hi, "+name+"!") $ python3 input.py What's your name? Hi, Blankname!
Fijate que el usuario nunca sabría que un EOFError ocurrió, esto puede ser usado para pasar valores por defecto en el caso de una entrada pobre o argumentos.
Salir y liberar sus recursos
Por lo general, Python libera todos los recursos que has llamado en tu programa automáticamente cuando sale, pero para ciertos procesos, es una buena práctica encerrar algunos recursos limitados with block.
A menudo verás esto en las llamadas de open(), donde el hecho de no liberar correctamente el archivo podría causar problemas para leer o escribir en el archivo más tarde.
$ nano openfile.py with open("testfile.txt","w") as file: file.write("let's write some text!\n") $ python3 openfile.py $ cat testfile.txt let's write some text!
El with block libera automáticamente todos los recursos solicitados dentro de él. Si quisiéramos asegurarnos de forma más explícita de que el archivo está cerrado, podríamos usar el comando atexit.register() para llamar a close()
$ nano openfile.py import atexit file=open("testfile.txt","w") file.write("let's write some text!\n") atexit.register(file.close)
Si los recursos son llamados sin usar un with block, asegúrese de liberarlos explícitamente en un comando atexit.
Salir luego de un tiempo
Si nos preocupa que nuestro programa nunca termine normalmente, podemos usar el módulo de multiprocesamiento de Python para asegurarnos de que nuestro programa termine.
$ nano waiting.py import time import sys from multiprocessing import Process integer=sys.argv[1] init=map(int, integer.strip('[]')) num=list(init)[0] def exclaim(int): time.sleep(int) print("You were very patient!") if __name__ == '__main__': program = Process(target=exclaim, args=(num,)) program.start() program.join(timeout=5) program.terminate() $ python3 waiting.py 7 $ python3 waiting.py 0 You were very patient!
¡Noten cómo el proceso no se completó cuando se le dijo a la función que esperara 7 segundos, pero se completó e imprimió lo que se suponía que debía hacer cuando se le dijo que esperara 0 segundos!
Salir utilizando una declaración de retorno
Si tenemos una sección de código que queremos usar para terminar todo el programa, en lugar de dejar que la sentencia de ruptura continúe el código fuera del bucle, podemos usar el retorno sys.exit() para salir del código completamente.
$ nano break.py import time import sys def stop(isTrue): for a in range(0,1): if isTrue: break else: print("You didn't want to break!") return sys.exit() mybool = False stop(mybool) print("You used break!")
Salir en el medio de una función
Si no queremos usar una declaración de retorno, todavía podemos llamar al sys.exit() para cerrar nuestro programa y proporcionar un retorno en otra rama. Usemos nuestro código de break.py otra vez.
$ nano break.py import time import sys def stop(isTrue): for a in range(0,1): if isTrue: word="bird" break else: print("You didn't want to break!") sys.exit() mybool = False print(stop(mybool))
Salir cuando se logran las condiciones
Si tenemos un bucle en nuestro código Python y queremos asegurarnos de que el código puede salir si encuentra un problema, podemos usar una bandera que puede comprobar para terminar el programa.
$ nano break.py import time import sys myflag=False def stop(val): global myflag while 1==1: val=val+1 print(val) if val%5==0: myflag=True if val%7==0: myflag=True if myflag: sys.exit() stop(1) $ python3 break.py 2 3 4 5
Salir al presionar una tecla
Si queremos mantener nuestro programa abierto en la consola hasta que pulsemos una tecla, podemos usar una entrada no vinculada() para cerrarlo.
$ nano holdopen.py input("Press enter to continue") $ python3 holdopen.py Press enter to continue $
También podemos pasar CTRL+C a la consola para darle a Python un carácter de Interrupción de Teclado. Incluso podemos manejar la excepción de KeyboardInterrupt como hemos manejado excepciones antes.
$ nano wait.py import time try: i=0 while 1==1: i=i+1 print(i) time.sleep(1) except KeyboardInterrupt: print("\nWhoops I took too long") raise SystemExit $ python3 wait.py 1 2 3 ^C Whoops I took too long
Salir de un programa multihilo
ESalir de un programa multihilo es un poco más complicado, ya que se llama a un simple sys.exit() desde el hilo que sólo saldrá del hilo actual. La forma “sucia” de hacerlo es usar os._exit()
$ nano threads.py import threading import os import sys import time integer=sys.argv[1] init=map(int, integer.strip('[]')) num=list(init)[0] def exclaim(int): time.sleep(int) os._exit(1) print("You were very patient!") if __name__ == '__main__': program = threading.Thread(target=exclaim, args=(num,)) program.start() program.join() print("This should print before the main thread terminates!") $ python3 threads.py 6 $
Como puedes ver, el programa no imprimió el resto del programa antes de salir, por eso os._exit() se reserva típicamente como último recurso, y llamar a Thread.join() desde el hilo principal es el método preferido para terminar un programa multihilo.
$ nano threads.py import threading import os import sys import time import atexit integer=sys.argv[1] init=map(int, integer.strip('[]')) num=list(init)[0] atexit.register(print,"Threads exited successfully!") def exclaim(int): time.sleep(int) print("You were very patient!") if __name__ == '__main__': program = threading.Thread(target=exclaim, args=(num,)) program.start() program.join() $ python3 threads.py 6 You were very patient! Threads exited successfully!
Terminar sin sys exit
sys.exit()
es sólo una de las muchas maneras en que podemos salir de nuestros programas Python, lo que sys.exit()
hace es elevar el nivel de SystemExit, así que podemos usar cualquier excepción Python incorporada o crear una propia!
$ nano myexception.py class MyException(Exception): pass try: raise MyException() except MyException: print("The exception works!") $ python3 myexception.py The exception works!
También podemos usar el os._exit() para decirle al sistema anfitrión que mate el proceso python, aunque esto no hace una limpieza atexit.
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os._exit(1)
Salida tras una excepción
Si queremos salir en cualquier excepción sin ningún tipo de manipulación, podemos usar nuestro bloque try-except para ejecutar os._exit().
Nota: esto también atrapará cualquier sys.exit(), quit(), exit(), o levantará llamadas a SystemExit, ya que todos ellos generan una excepción de SystemExit.
$ python3 Python 3.8.2 (default, Apr 1 2020, 15:52:55) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> try: ... quit() ... except: ... os._exit(1) ... $ echo $? 1
Salir y reiniciar
Finalmente, exploraremos lo que hacemos para salir de Python y reiniciar el programa, lo cual es útil en muchos casos.
$ nano restart.py import atexit import os atexit.register(os.system,"python3 restart.py") try: n=0 while 1==1: n=n+1 if n%5==0: raise SystemExit except: print("Exception raised!") $ python3 restart.py Exception raised! Exception raised! ... Exception raised! ^Z [3]+ Stopped python3 restart.py
Espero que el tutorial les sea útil. Sigan regresando.
Gracias.
Fundadora de LikeGeeks. Estoy trabajando como administrador de sistemas Linux desde 2010. Soy responsable de mantener, proteger y solucionar problemas de servidores Linux para múltiples clientes de todo el mundo. Me encanta escribir guiones de shell y Python para automatizar mi trabajo.