Python en Español

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í.

 

 

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

Salida para el código input.py si el usuario pasa un carácter EOF

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 para input.py mientras se usa atexit

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

Ejemplos de salir del intérprete interactivo de Python usando quit, exit, sys.exit y raise SystemExit

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!

Pasar un carácter EOF a input.py para demostrar el manejo de excepciones

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!

Pasar un carácter EOF a input.py para demostrar el uso de manejo de errores aún más por defecto a un valor

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!

Usar con para liberar el recurso abierto

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!

Mostrar que la declaración de unión agota el proceso

¡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!")

El código salió de la rama de retorno en lugar de la rama de corte

 

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))

¡Podemos salir de Python en el medio de la función!

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

Salimos del programa cuando detectó que era divisible por 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

De hecho, detectamos una excepción KeyboardInterrupt y tomamos medidas al respecto

 

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
$

El hilo llama a os exit antes de que pueda hacer otra cosa o hacer la limpieza correctamente

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!

Usamos el comando de unión, todos los hilos se cierran con gracia

 

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!

Usamos definiciones de clase para crear una nueva excepción que cierra el programa.

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)

Os exit is a 'dirty' way of closing a Python program because it doesn't exit as gracefully as other exit forms

 

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

El uso de un intento no enumerado excepto el bloque puede detectar una excepción SystemExit y evitar que su programa se cierre

 

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

Al usar el módulo atexit y el manejo de excepciones, puede reiniciar su programa después de que salga

Espero que el tutorial les sea útil. Sigan regresando.

Gracias.

Mokhtar Ebrahim
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.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *