Qu'est-ce qu'un sous-processus en Python ? [5 exemples d'utilisation]

Publié: 2021-05-23

Les sous-processus vous permettent d'interagir à un tout nouveau niveau avec le système d'exploitation.

Notre ordinateur exécute des sous-processus tout le temps. En fait, rien qu'en lisant cet article, vous exécutez de nombreux processus comme un gestionnaire de réseau ou le navigateur Internet lui-même.

Ce qui est bien à ce sujet, c'est que toute action que nous effectuons sur notre ordinateur implique l'invocation d'un sous-processus. Cela reste vrai même si nous écrivons un simple script "hello world" en python.

Le concept du sous - processus peut sembler obscur même si vous apprenez la programmation depuis un certain temps. Cet article examinera en profondeur le concept principal du sous-processus et comment utiliser la bibliothèque standard de sous-processus Python.

À la fin de ce didacticiel, vous allez :

  • Comprendre le concept de sous-processus
  • Avoir appris les bases de la bibliothèque de sous-processus Python
  • Pratiquez vos compétences Python avec des exemples utiles

Entrons-y

Le concept de sous-processus

En gros, un sous-processus est un processus informatique créé par un autre processus.

Nous pouvons considérer un sous-processus comme un arbre, dans lequel chaque processus parent a des processus enfants exécutés derrière lui. Je sais que cela peut être assez déroutant, mais voyons cela avec un simple graphique.

Il existe plusieurs façons de visualiser le processus en cours sur notre ordinateur. Par exemple, sous UNIX (Linux et MAC), nous avons htop, qui est un visualiseur de processus interactif.

Visionneuse de processus Htop

Le mode arborescence est l'outil le plus utile pour examiner les sous-processus en cours d'exécution. Nous pouvons l'activer avec F5 .

Si nous examinons de près la section des commandes, nous pouvons remarquer la structure des processus en cours d'exécution sur notre ordinateur.

Structure de processus Htop
Tout commence par /sbin/init qui est la commande qui démarre chaque processus sur notre ordinateur. À partir de ce point, nous pouvons voir le début d'autres processus comme xfce4-screenshoter et le xfce4-terminal (ce qui conduit à encore plus de sous-processus)

En regardant Windows, nous avons le mythique gestionnaire de tâches qui s'avère utile lors de la suppression de ces programmes en panne sur notre machine.

Gestionnaire de tâches Windows

Maintenant, nous avons un concept clair comme du cristal. Voyons comment nous pouvons implémenter des sous-processus en Python.

Sous-processus en Python

Un sous-processus en Python est une tâche qu'un script python délègue au système d'exploitation (OS).

La bibliothèque de sous-processus nous permet d'exécuter et de gérer des sous-processus directement depuis Python. Cela implique de travailler avec l'entrée standard stdin , la sortie standard stdout et les codes de retour.

Nous n'avons pas besoin de l'installer avec PIP, puisqu'il fait partie de la bibliothèque standard Python.

Par conséquent, nous pouvons commencer à utiliser des sous-processus en python simplement en important le module.

 import subprocess # Using the module ....

Remarque : pour suivre cet article, vous devez disposer de Python 3.5 +

Pour vérifier la version de python que vous possédez actuellement, exécutez simplement.

 ❯ python --version Python 3.9.5 # My result

Si la version Python que vous obtenez est 2.x, vous pouvez utiliser la commande suivante

 python3 --version

Poursuivant le sujet, l'idée principale derrière la bibliothèque de sous-processus est de pouvoir interagir avec le système d'exploitation en exécutant toutes les commandes que nous voulons, directement à partir de l'interpréteur Python.

Cela signifie que nous pouvons faire ce que nous voulons, tant que notre système d'exploitation nous le permet (et tant que vous ne supprimez pas votre système de fichiers racine).

Voyons comment l'utiliser en créant un script simple qui liste les fichiers du répertoire courant.

Première application de sous-processus

Tout d'abord, créons un fichier list_dir.py . Ce sera le fichier où nous allons expérimenter la liste des fichiers.

 touch list_dir.py

Ouvrons maintenant ce fichier et utilisons le code suivant.

 import subprocess subprocess.run('ls')

Tout d'abord, nous importons le module de sous-processus, puis utilisons la fonction run qui s'exécute, la commande que nous passons en argument.

Cette fonction a été introduite dans Python 3.5, en tant que raccourci convivial vers subprocess.Popen. La fonction subprocess.run nous permet d'exécuter une commande et d'attendre qu'elle se termine, contrairement à Popen où nous avons la possibilité d'appeler communiquer plus tard.

En parlant de la sortie du code, ls est une commande UNIX qui répertorie les fichiers du répertoire dans lequel vous vous trouvez. Par conséquent, si vous exécutez cette commande, vous obtiendrez une liste des fichiers présents dans le répertoire actuel.

 ❯ python list_dir.py example.py LICENSE list_dir.py README.md

Remarque : N'oubliez pas que si vous êtes sous Windows, vous devrez utiliser différentes commandes. Par exemple, au lieu d'utiliser "ls", vous pouvez utiliser "dir"

Cela peut sembler trop simple, et vous avez raison. Vous voulez avoir une approche complète de toute la puissance que la coque vous apporte. Apprenons donc à passer des arguments au shell avec un sous-processus.

Par exemple pour lister aussi les fichiers cachés (Ceux qui commencent par un point), et aussi lister toutes les métadonnées des fichiers, nous écrivons le code suivant.

 import subprocess # subprocess.run('ls') # Simple command subprocess.run('ls -la', shell=True)

Nous exécutons cette commande sous forme de chaîne et utilisons l'argument shell . Cela signifie que nous invoquons un shell au début de l'exécution de notre sous-processus et que l'argument de commande est interprété directement par le shell.

Cependant, l'utilisation de shell=True a de nombreux inconvénients, et les pires sont les possibles fuites de sécurité. Vous pouvez lire à leur sujet dans la documentation officielle.

La meilleure façon de passer des commandes à la fonction run est d'utiliser une liste où lst[0] est la commande à appeler (ls dans ce cas) et lst[n] sont les arguments de cette commande.

Si nous le faisons, notre code ressemblera à ceci.

 import subprocess # subprocess.run('ls') # Simple command # subprocess.run('ls -la', shell=True) # Dangerous command subprocess.run(['ls', '-la'])

Si nous voulons stocker la sortie standard d'un sous-processus dans une variable, nous pouvons le faire en définissant l'argument capture_output sur true.

 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'

Pour accéder à la sortie d'un processus, nous utilisons l'attribut d'instance stdout .

Dans ce cas, nous voulons stocker la sortie sous forme de chaîne, au lieu d'octets et nous pouvons le faire en définissant l'argument text sur true.

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

Parfait, maintenant que nous connaissons les bases de la bibliothèque de sous - processus , il est temps de passer à quelques exemples d'utilisation.

Exemples d'utilisation de sous-processus en Python

Dans cette section, nous allons passer en revue quelques utilisations pratiques de la bibliothèque de sous-processus. Vous pouvez tous les vérifier dans ce référentiel Github.

Vérificateur de programme

L'une des principales utilisations de cette bibliothèque est la possibilité d'effectuer des opérations simples sur le système d'exploitation.

Par exemple, un simple script qui vérifie si un programme est installé. Sous Linux, nous pouvons le faire avec la commande 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)

Remarque : Sous UNIX, lorsqu'une commande réussit, son code d'état est 0. Sinon, quelque chose s'est mal passé pendant l'exécution

Puisque nous n'utilisons pas l'argument shell=True , nous pouvons prendre l'entrée de l'utilisateur en toute sécurité. De plus, nous pouvons vérifier si l'entrée est un programme valide avec un modèle regex.

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

Dans ce cas, nous obtenons les programmes de l'utilisateur et utilisons une expression regex qui certifie que la chaîne de programme ne comprend que des lettres et des chiffres. Nous vérifions l'existence de chaque programme avec une boucle for.

Grep simple en Python

Votre ami Tom a une liste de modèles dans un fichier texte et un autre fichier volumineux dans lequel il souhaite obtenir le nombre de correspondances pour chaque modèle. Il passait des heures à exécuter la commande grep pour chaque modèle.

Heureusement, vous savez comment résoudre ce problème avec Python, et vous l'aiderez à accomplir cette tâche en quelques secondes.

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

En examinant ce fichier, nous définissons deux variables qui sont les noms de fichiers avec lesquels nous voulons travailler. Ensuite, nous ouvrons le fichier qui contient tous les modèles et nous les parcourons. Ensuite, nous appelons un sous-processus qui exécute une commande grep avec l'indicateur "-c" (compte moyen) et déterminons la sortie de la correspondance avec un conditionnel.

Si vous exécutez ce fichier (n'oubliez pas que vous pouvez télécharger les fichiers texte à partir du référentiel Github)

Configurer un virtualenv avec un sous-processus

L'automatisation des processus est l'une des choses les plus intéressantes que vous puissiez faire avec Python. Ce type de script peut vous faire gagner des heures par semaine.

Par exemple, nous allons créer un script d'installation qui crée un environnement virtuel pour nous et essaie de trouver un fichier requirements.txt dans le répertoire actuel pour installer toutes les dépendances.

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

Dans ce cas, nous utilisons plusieurs processus et analysons les données dont nous avons besoin dans notre script python. Nous utilisons également la bibliothèque pathlib qui nous permet de déterminer si le fichier requirements.txt existe.

Si vous exécutez le fichier python, vous obtiendrez des messages utiles sur ce qui se passe avec le système d'exploitation.

 ❯ 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"

Notez que nous obtenons la sortie du processus d'installation car nous ne redirigeons pas la sortie standard vers une variable.

Exécuter un autre langage de programmation

Nous pouvons exécuter d'autres langages de programmation avec python et obtenir la sortie de ces fichiers. Ceci est possible car les sous-processus interagissent directement avec le système d'exploitation.

Par exemple, créons un programme hello world en C++ et Java. Pour exécuter le fichier suivant, vous devrez installer les compilateurs C++ et 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"); } }


Je sais que cela semble beaucoup de code par rapport à une simple ligne Python, mais c'est juste à des fins de test.

Nous allons créer un script Python qui exécute tous les fichiers C++ et Java dans un répertoire. Pour ce faire, nous voulons d'abord obtenir une liste de fichiers en fonction de l'extension de fichier, et glob nous permet de le faire facilement !

 from glob import glob # Gets files with each extension java_files = glob('*.java') cpp_files = glob('*.cpp')

Après cela, nous pouvons commencer à utiliser des sous-processus pour exécuter chaque type de fichier.

 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)

Une petite astuce consiste à utiliser la bande de fonction de chaîne pour modifier la sortie et obtenir uniquement ce dont nous avons besoin.

Remarque : veillez à exécuter de gros fichiers Java ou C++ car nous chargeons leur sortie en mémoire et cela pourrait produire une fuite de mémoire.

Ouvrir des programmes externes

Nous pouvons exécuter d'autres programmes simplement en appelant leur emplacement binaire via un sous-processus.

Essayons-le en ouvrant brave , mon navigateur Web préféré.

 import subprocess subprocess.run('brave')

Cela ouvrira une instance de navigateur, ou simplement un autre onglet si vous avez déjà exécuté le navigateur.

Navigateur ouvert

Comme avec tout autre programme qui accepte les drapeaux, nous pouvons les utiliser pour produire le comportement souhaité.

 import subprocess subprocess.run(['brave', '--incognito'])

Drapeau de navigation privée

Pour résumer

Un sous-processus est un processus informatique créé par un autre processus. Nous pouvons vérifier les processus exécutés par notre ordinateur avec des outils tels que htop et le gestionnaire de tâches.

Python a sa propre bibliothèque pour travailler avec des sous-processus. Actuellement, la fonction run nous offre une interface simple pour créer et gérer des sous-processus.

Nous pouvons créer n'importe quel type d'application avec eux car nous interagissons directement avec le système d'exploitation.

Enfin, n'oubliez pas que la meilleure façon d'apprendre est de créer quelque chose que vous aimeriez utiliser.