¿Qué es un subproceso en Python? [5 ejemplos de uso]
Publicado: 2021-05-23Los subprocesos le permiten interactuar en un nivel totalmente nuevo con el sistema operativo.
Nuestra computadora ejecuta subprocesos todo el tiempo. De hecho, con solo leer este artículo, está ejecutando muchos procesos, como un administrador de red o el navegador de Internet en sí.
Lo bueno de esto es que cualquier acción que hacemos en nuestra computadora implica invocar un subproceso. Eso sigue siendo cierto incluso si estamos escribiendo un simple script de "hola mundo" en Python.
El concepto de subproceso puede parecer oscuro incluso si ha estado aprendiendo programación durante un tiempo. Este artículo analizará en profundidad el concepto principal del subproceso y cómo utilizar la biblioteca estándar de subprocesos de Python.
Al final de este tutorial, podrá:
- Comprender el concepto de subproceso
- Han aprendido los conceptos básicos de la biblioteca de subprocesos de Python.
- Practicó sus habilidades de Python con ejemplos útiles
Vamos a entrar en eso
El concepto de subproceso
En términos generales, un subproceso es un proceso informático creado por otro proceso.
Podemos pensar en un subproceso como un árbol, en el que cada proceso padre tiene procesos secundarios ejecutándose detrás de él. Sé que esto puede ser bastante confuso, pero veámoslo con un gráfico simple.

Hay varias formas en que podemos visualizar el proceso que se ejecuta en nuestra computadora. Por ejemplo, en UNIX (Linux y MAC) tenemos htop, que es un visor de procesos interactivo.

El modo de árbol es la herramienta más útil para echar un vistazo a los subprocesos en ejecución. Podemos activarlo con F5 .
Si echamos un vistazo de cerca a la sección de comandos, podemos notar la estructura de los procesos que se ejecutan en nuestra computadora.

Todo comienza con / sbin / init, que es el comando que inicia cada proceso en nuestra computadora. A partir de ese punto, podemos ver el inicio de otros procesos como xfce4-screenshoter y el xfce4-terminal (que conduce a aún más subprocesos)
Echando un vistazo a Windows, tenemos el mítico administrador de tareas que resulta útil al eliminar esos programas que fallan en nuestra máquina.

Ahora tenemos un concepto muy claro. Veamos cómo podemos implementar subprocesos en Python.
Subprocesos en Python
Un subproceso en Python es una tarea que un script de Python delega al sistema operativo (SO).
La biblioteca de subprocesos nos permite ejecutar y administrar subprocesos directamente desde Python. Eso implica trabajar con stdin entrada stdin , stdout salida estándar y códigos de retorno.
No tenemos que instalarlo con PIP, ya que es parte de la biblioteca estándar de Python.
Por lo tanto, podemos comenzar a usar subprocesos en Python simplemente importando el módulo.
import subprocess # Using the module ....Nota: Para seguir este artículo, debe tener Python 3.5 +
Para verificar la versión de Python que tiene actualmente, simplemente ejecute.
❯ python --version Python 3.9.5 # My resultEn caso de que la versión de Python que obtenga es 2.x, puede usar el siguiente comando
python3 --versionContinuando con el tema, la idea principal detrás de la biblioteca de subprocesos es poder interactuar con el sistema operativo ejecutando los comandos que queramos, directamente desde el intérprete de Python.
Eso significa que podemos hacer lo que queramos, siempre que nuestro sistema operativo nos lo permita (y siempre que no elimine su sistema de archivos raíz).
Veamos cómo usarlo creando un script simple que enumere los archivos del directorio actual.
Primera aplicación de subproceso
Primero, creemos un archivo list_dir.py . Este será el archivo donde vamos a experimentar la lista de archivos.
touch list_dir.pyAhora abramos ese archivo y usemos el siguiente código.
import subprocess subprocess.run('ls')Primero, estamos importando el módulo de subproceso, y luego usando la función run que se ejecuta, el comando que pasamos como argumento.
Esta función se introdujo en Python 3.5, como un atajo amigable para subprocess.Popen. La función subprocess.run nos permite ejecutar un comando y esperar a que termine, a diferencia de Popen donde tenemos la opción de llamar a comunicarse más tarde.
Hablando de la salida del código, ls es un comando de UNIX que enumera los archivos del directorio en el que se encuentra. Por lo tanto, si ejecuta este comando, obtendrá una lista de los archivos presentes en el directorio actual.
❯ python list_dir.py example.py LICENSE list_dir.py README.mdNota: Tenga en cuenta que si está en Windows, deberá usar diferentes comandos. Por ejemplo, en lugar de usar "ls" , puede usar "dir"
Esto puede parecer demasiado simple y tiene razón. Quieres tener un enfoque completo de todo el poder que te brinda el caparazón. Entonces, aprendamos cómo pasar argumentos al shell con subproceso.
Por ejemplo para listar también los archivos ocultos (aquellos que comienzan con un punto), y también listar todos los metadatos de los archivos, escribimos el siguiente código.
import subprocess # subprocess.run('ls') # Simple command subprocess.run('ls -la', shell=True)Ejecutamos este comando como una cadena y usamos el argumento shell . Eso significa que estamos invocando un shell al comienzo de la ejecución de nuestro subproceso, y el argumento del comando es interpretado directamente por el shell.
Sin embargo, use shell = True tiene muchas desventajas, y las peores son las posibles fugas de seguridad. Puedes leer sobre ellos en la documentación oficial.
La mejor manera de pasar comandos a la función de ejecución es usar una lista donde lst [0] es el comando a llamar (ls en este caso) y lst [n] son los argumentos de ese comando.
Si lo hacemos, nuestro código se verá así.
import subprocess # subprocess.run('ls') # Simple command # subprocess.run('ls -la', shell=True) # Dangerous command subprocess.run(['ls', '-la'])Si queremos almacenar la salida estándar de un subproceso en una variable, podemos hacerlo estableciendo el argumento capture_output en verdadero.
list_of_files = subprocess.run(['ls', '-la'], capture_output=True) print(list_of_files.stdout) ❯ python list_dir.py b'total 36\ndrwxr-xr-x 3 daniel daniel 4096 may 20 21:08 .\ndrwx------ 30 daniel daniel 4096 may 20 18:03 ..\n-rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py\ndrwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git\n-rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore\n-rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py\n-rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE\n-rw-r--r-- 1 daniel daniel 216 may 20 22:12 list_dir.py\n-rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.md\n'Para acceder a la salida de un proceso, usamos el atributo de instancia stdout .
En este caso, queremos almacenar la salida como una cadena, en lugar de bytes, y podemos hacerlo configurando el argumento de texto como verdadero.
list_of_files = subprocess.run(['ls', '-la'], capture_output=True, text=True) print(list_of_files.stdout) ❯ python list_dir.py total 36 drwxr-xr-x 3 daniel daniel 4096 may 20 21:08 . drwx------ 30 daniel daniel 4096 may 20 18:03 .. -rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py drwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git -rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore -rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py -rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE -rw-r--r-- 1 daniel daniel 227 may 20 22:14 list_dir.py -rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.mdPerfecto, ahora que conocemos los conceptos básicos de la biblioteca de subprocesos , es hora de pasar a algunos ejemplos de uso.
Ejemplos de uso de subprocesos en Python
En esta sección, revisaremos algunos usos prácticos de la biblioteca de subprocesos. Puedes consultarlos todos en este repositorio de Github.
Comprobador de programas
Uno de los principales usos de esta biblioteca es la capacidad de realizar operaciones sencillas del sistema operativo.
Por ejemplo, una secuencia de comandos simple que comprueba si un programa está instalado. En Linux, podemos hacer esto con el comando which .

'''Program checker with subprocess''' import subprocess program = 'git' process = subprocess. run(['which', program], capture_output=True, text=True) if process.returncode == 0: print(f'The program "{program}" is installed') print(f'The location of the binary is: {process.stdout}') else: print(f'Sorry the {program} is not installed') print(process.stderr)Nota: En UNIX, cuando un comando tiene éxito, su código de estado es 0. De lo contrario, algo salió mal durante la ejecución.
Como no estamos usando el argumento shell = True , podemos tomar la entrada del usuario de forma segura. Además, podemos verificar si la entrada es un programa válido con un patrón de expresiones regulares.
import subprocess import re programs = input('Separe the programs with a space: ').split() secure_pattern = '[\w\d]' for program in programs: if not re.match(secure_pattern, program): print("Sorry we can't check that program") continue process = subprocess. run( ['which', program], capture_output=True, text=True) if process.returncode == 0: print(f'The program "{program}" is installed') print(f'The location of the binary is: {process.stdout}') else: print(f'Sorry the {program} is not installed') print(process.stderr) print('\n')En este caso, obtenemos los programas del usuario y usamos una expresión regular que certifica que la cadena del programa solo incluye letras y dígitos. Comprobamos la existencia de cada programa con un bucle for a.
Grep simple en Python
Tu amigo Tom tiene una lista de patrones en un archivo de texto y otro archivo grande en el que quiere obtener el número de coincidencias para cada patrón. Pasaría horas ejecutando el comando grep para cada patrón.
Afortunadamente, sabes cómo resolver este problema con Python y lo ayudarás a realizar esta tarea en pocos segundos.
import subprocess patterns_file = 'patterns.txt' readfile = 'romeo-full.txt' with open(patterns_file, 'r') as f: for pattern in f: pattern = pattern.strip() process = subprocess.run( ['grep', '-c', f'{pattern}', readfile], capture_output=True, text=True) if int(process.stdout) == 0: print( f'The pattern "{pattern}" did not match any line of {readfile}') continue print(f'The pattern "{pattern}" matched {process.stdout.strip()} times')Echando un vistazo a este archivo, definimos dos variables que son los nombres de archivo con los que queremos trabajar. Luego abrimos el archivo que contiene todos los patrones y los iteramos. A continuación, llamamos a un subproceso que ejecuta un comando grep con la bandera "-c" (significa recuento) y determinamos la salida de la coincidencia con un condicional.
Si ejecuta este archivo (recuerde que puede descargar los archivos de texto desde el repositorio de Github)
Configurar un virtualenv con subproceso
Una de las mejores cosas que puede hacer con Python es la automatización de procesos. Este tipo de secuencia de comandos puede ahorrarle horas a la semana.
Por ejemplo, vamos a crear un script de configuración que crea un entorno virtual para nosotros e intenta encontrar un archivo requirements.txt en el directorio actual para instalar todas las dependencias.
import subprocess from pathlib import Path VENV_NAME = '.venv' REQUIREMENTS = 'requirements.txt' process1 = subprocess.run(['which', 'python3'], capture_output=True, text=True) if process1.returncode != 0: raise OSError('Sorry python3 is not installed') python_bin = process1.stdout.strip() print(f'Python found in: {python_bin}') process2 = subprocess.run('echo "$SHELL"', shell=True, capture_output=True, text=True) shell_bin = process2.stdout.split('/')[-1] create_venv = subprocess.run([python_bin, '-m', 'venv', VENV_NAME], check=True) if create_venv.returncode == 0: print(f'Your venv {VENV_NAME} has been created') pip_bin = f'{VENV_NAME}/bin/pip3' if Path(REQUIREMENTS).exists(): print(f'Requirements file "{REQUIREMENTS}" found') print('Installing requirements') subprocess.run([pip_bin, 'install', '-r', REQUIREMENTS]) print('Process completed! Now activate your environment with "source .venv/bin/activate"') else: print("No requirements specified ...")En este caso, estamos usando varios procesos y analizando los datos que necesitamos en nuestro script de Python. También estamos usando la biblioteca pathlib que nos permite calcularlo si existe el archivo requirements.txt .
Si ejecuta el archivo python, obtendrá algunos mensajes útiles sobre lo que está sucediendo con el sistema operativo.
❯ python setup.py Python found in: /usr/bin/python3 Your venv .venv has been created Requirements file "requirements.txt" found Installing requirements Collecting asgiref==3.3.4 ....... Process completed! Now activate your environment with "source .venv/bin/activate"Tenga en cuenta que obtenemos el resultado del proceso de instalación porque no estamos redirigiendo el resultado estándar a una variable.
Ejecute otro lenguaje de programación
Podemos ejecutar otros lenguajes de programación con python y obtener el resultado de esos archivos. Esto es posible porque los subprocesos interactúan directamente con el sistema operativo.
Por ejemplo, creemos un programa de hola mundo en C ++ y Java. Para ejecutar el siguiente archivo, deberá instalar los compiladores C ++ y Java.
helloworld.cpp
#include <iostream> int main(){ std::cout << "This is a hello world in C++" << std::endl; return 0; }
helloworld.java
class HelloWorld{ public static void main(String args[]){ System.out.println("This is a hello world in Java"); } }
Sé que esto parece mucho código en comparación con una simple línea de Python, pero esto es solo para fines de prueba.
Vamos a crear un script Python que ejecute todos los archivos C ++ y Java en un directorio. Para hacer esto, primero queremos obtener una lista de archivos dependiendo de la extensión del archivo, ¡y glob nos permite hacerlo fácilmente!
from glob import glob # Gets files with each extension java_files = glob('*.java') cpp_files = glob('*.cpp')Después de eso, podemos comenzar a usar subprocesos para ejecutar cada tipo de archivo.
for file in cpp_files: process = subprocess.run(f'g++ {file} -o out; ./out', shell=True, capture_output=True, text=True) output = process.stdout.strip() + ' BTW this was runned by Python' print(output) for file in java_files: without_ext = file.strip('.java') process = subprocess.run(f'java {file}; java {without_ext}',shell=True, capture_output=True, text=True) output = process.stdout.strip() + ' A Python subprocess runned this :)' print(output)Un pequeño truco es usar la función de cadena strip para modificar la salida y obtener solo lo que necesitamos.
Nota: Tenga cuidado al ejecutar archivos grandes de Java o C ++ ya que estamos cargando su salida en la memoria y eso podría producir una pérdida de memoria.
Abrir programas externos
Podemos ejecutar otros programas simplemente llamando a la ubicación de sus binarios a través de un subproceso.
Probémoslo abriendo brave , mi navegador web preferido.
import subprocess subprocess.run('brave')Esto abrirá una instancia del navegador, o simplemente otra pestaña si ya lo ha ejecutado.

Como con cualquier otro programa que acepta banderas, podemos usarlas para producir el comportamiento deseado.
import subprocess subprocess.run(['brave', '--incognito']) 
Para resumir
Un subproceso es un proceso informático creado por otro proceso. Podemos verificar los procesos que nuestra computadora está ejecutando con herramientas como htop y el administrador de tareas.
Python tiene su propia biblioteca para trabajar con subprocesos. Actualmente, la función de ejecución nos brinda una interfaz simple para crear y administrar subprocesos.
Podemos crear cualquier tipo de aplicación con ellos porque estamos interactuando directamente con el SO.
Finalmente, recuerde que la mejor manera de aprender es crear algo que le gustaría usar.
