El módulo subprocess de Python te permite controlar, ejecutar y evaluar programas externos dentro del código. Las dos funciones más im­po­r­ta­n­tes de esta he­rra­mie­n­ta son run() y popen().

¿Qué es Python subprocess?

El módulo subprocess forma parte del in­ve­n­ta­rio del lenguaje de pro­gra­ma­ción Python desde la versión 2.4. Es una he­rra­mie­n­ta muy completa y potente que puedes utilizar para ejecutar otros programas o comandos dentro de tu código. No solo es posible abrir programas, sino también controlar y adaptar el flujo de datos. subprocess de Python ofrece numerosos métodos y funciones, los más im­po­r­ta­n­tes de los cuales veremos en este artículo y ex­pli­ca­re­mos mediante ejemplos.

subprocess: fu­n­cio­na­li­dad con run()

Antes de nada, sin embargo, tiene sentido echar un vistazo a la es­tru­c­tu­ra y fu­n­cio­na­li­dad básica de subprocess de Python. El módulo se utiliza para ejecutar su­b­pro­ce­sos. Python funciona en la jerarquía padre-hijo como un proceso padre que crea un proceso su­bo­r­di­na­do. La función más utilizada dentro del módulo es run(). Esto te permite iniciar un proceso a través de Python y solo comienza otros pasos una vez que se ha co­m­ple­ta­do.

Ejemplo de cómo funciona subprocess de Python con run()

Uti­li­za­re­mos esta función en nuestro primer ejemplo para ilustrar cómo funciona subprocess de Python. Para ello, primero im­po­r­ta­mos los módulos subprocess y sys y luego eje­cu­ta­mos una petición sencilla. El código co­rre­s­po­n­die­n­te es el siguiente:

import subprocess 
import sys 
result = subprocess.run([sys.executable, "-c", "print('hola')"])
python

El resultado es el siguiente:

hola
python
  • subprocess.run: esta es la función real. Recibe una lista de cadenas que contienen el comando a ejecutar. run() ejecuta un nuevo programa Python.
  • sys.executable: es la ruta absoluta que lleva al archivo Python con el que ori­gi­na­l­me­n­te llamaste a tu programa. Un ejemplo de esta ruta podría ser /local/usuario/bin/ejemplo.
  • -c: es una opción de línea de comandos con la que se pasa la cadena de ca­ra­c­te­res nombrada para su ejecución. Para nuestro ejemplo, se trata de un programa que produce la palabra “hola”.

Ejecutar subprocess de Python con un script

Para probar cómo utilizar el módulo para un script pe­r­so­na­li­za­do, puedes probar el siguiente ejemplo. Para ello, crea primero un script sencillo en formato .py y guárdalo como “ejemplo-script.py”

print("Hoy hace buen tiempo")
python

Para ejecutar este archivo con subprocess, utiliza el siguiente código:

import subprocess 
result = subprocess.run(["python", "ejemplo_script.py"], capture_output=True, text=True) 
print(result.stdout)
python

El resultado es el siguiente:

Hoy hace buen tiempo
python

Abrir programas externos

En principio, es posible abrir cualquier programa con subprocess de Python y la función run(). El único requisito para ello es que conozcas el nombre exacto o la ruta bajo la que se encuentra ese programa en tu sistema. En el siguiente código, por ejemplo, abrimos el Bloc de Notas:

import subprocess 
subprocess.run(["notepad"])
python

CompletedProcess y captura de salidas externas

Después de estos sencillos ejemplos, vamos a ver ahora la captura de una salida externa. En este caso, ejecutas un programa externo con subprocess en Python, como vimos an­te­rio­r­me­n­te, pero en lugar de si­m­ple­me­n­te ejecutar el programa, obtienes un objeto CompletedProcess. Ya hemos hecho algunos ajustes ne­ce­sa­rios en un ejemplo anterior, pero ahora los ex­pli­ca­re­mos en detalle. Nuestro punto de partida será nue­va­me­n­te el primer código. Sin embargo, ahora lo ada­p­ta­re­mos:

import subprocess 
import sys 
result = subprocess.run([sys.executable, "-c", "print('hola')"], capture_output=True, text=True) 
print("La salida estándar es:", result.stdout) 
print("El error estándar es:", result.stderr)
python

Una vez más, ordenamos al sistema que emita la cadena de ca­ra­c­te­res “hola”. Esto se hace en un proceso su­bo­r­di­na­do. Lo nuevo, sin embargo, son los dos ar­gu­me­n­tos capture_output=True y text=True, que también pasamos a run(). Si la sentencia se ejecuta y no hay errores, recibirás un objeto CompletedProcess con un enlace a result. El objeto contiene in­fo­r­ma­ción sobre el código de salida del programa que se quiere ejecutar y se lo pasa a result.stdout y result.stderr. stdout denota la salida estándar, stderr los posibles errores estándar. Usamos text=True para imprimir la salida como una cadena de ca­ra­c­te­res. Como no se espera ningún error estándar, nuestro resultado es el siguiente:

La salida estándar es: hola 
 
Este es el error estándar:
python

Para ilustrar mejor cómo funciona, crearemos el siguiente ejemplo para que stderr no quede vacío esta vez. El código co­rre­s­po­n­die­n­te es éste:

import subprocess 
import sys 
result = subprocess.run([sys.executable, "-c", "raise ValueError('error')"], capture_output=True, text=True) 
print("La salida estándar es:", result.stdout) 
print("Este es el error estándar:", result.stderr)
python

Mientras que la salida estándar permanece vacía esta vez, ahora hay una salida para stderr:

La salida estándar es: 
Este es el error estándar: Traceback (most recent call last): 
File "<string>", line 1, in <module> 
ValueError: error
python

Ejecución desde una función

Con subprocess también puedes incluir un comando di­re­c­ta­me­n­te en el código. En este caso, el código podría ser el siguiente:

import subprocess 
result = subprocess.run(["C:/Users/name/anaconda3/python", "-c", "print('Esta salida se tomó directamente de una función')"], capture_output=True, text=True, shell=True) 
print("La salida estándar es:", result.stdout)
python

Nuestro resultado es:

La salida estándar es: Esta salida se tomó directamente de una función
python

Detener o finalizar procesos

Otro uso muy útil de subprocess se consigue mediante la in­ter­ac­ción de run() con el argumento timeout. Te permite detener un programa externo si tarda demasiado en eje­cu­tar­se. Utiliza la función time.sleep para esto. El código apropiado es este:

import subprocess 
import sys 
result = subprocess.run([sys.executable, "-c", "import time; time.sleep(3)"], timeout=1)
python

El proceso su­bo­r­di­na­do utiliza time.sleep para su­s­pe­n­de­r­se durante tres segundos. Sin embargo, como has dado in­s­tru­c­cio­nes al sistema para que active un tiempo de espera después de un segundo mediante timeout=1, el resultado es una excepción TimeoutExpired.

subprocess de Python con popen()

Aunque run() es la función subprocess de Python que se utiliza con más fre­cue­n­cia, hay otras clases im­po­r­ta­n­tes que pueden ser útiles. Entre ellas está popen(). Esta clase es más o menos la su­b­e­s­tru­c­tu­ra de subprocess y es algo más compleja de usar que run(). Sin embargo, popen() te da más control sobre la ejecución y te permite in­ter­ac­tuar con la entrada y la salida. La clase debe su nombre a un comando UNIX y significa “pipe open”.

Casi todos los ar­gu­me­n­tos que puedes utilizar con run() también están pe­r­mi­ti­dos para popen(). Sin embargo, a di­fe­re­n­cia de run(), esta función no espera a que se complete un proceso, sino que inicia un segundo en paralelo. Podemos ilustrar cómo funciona con un ejemplo sencillo:

import subprocess 
from time import sleep 
 
def poll_and_read(process): 
    print(f"Esta es la salida después de poll(): {process.poll()}") 
    print(f"Esta es la salida estándar: {process.stdout.read().decode('utf-8')}") 
 
process = subprocess.Popen(["python", "timer.py", "3"], stdout=subprocess.PIPE) 
 
poll_and_read(process) 
sleep(2) 
 
poll_and_read(process) 
sleep(2) 
 
poll_and_read(process) 
 
process.wait() 
print(f"Código de salida del proceso: {process.returncode}")
python

Uti­li­za­mos el método .poll() para comprobar si el proceso sigue en marcha o ya ha fi­na­li­za­do. Si aún está en ejecución, se muestra el valor “None”. A co­n­ti­nua­ción, el método muestra el código de salida. Con .read() se leen todos los bytes que se en­cue­n­tran en .stdout. Si ejecutas el código, primero recibirás el valor “None” y luego el valor contenido pre­via­me­n­te en .stdout. Esto continúa hasta que el proceso ha terminado. Entonces poll() recibe el valor “0”.

Consejo

Despliega apli­ca­cio­nes y páginas web di­re­c­ta­me­n­te con GitHub: con Deploy Now de IONOS, te be­ne­fi­cia­rás de una co­n­fi­gu­ra­ción más rápida, flujos de trabajo op­ti­mi­za­dos y una excelente es­ca­la­bi­li­dad. Encuentra la tarifa que se adapta a tus ne­ce­si­da­des.

Ir al menú principal