HOWTO · Python

Appeler un programme externe en Python

Ce tutoriel montre comment exécuter des programmes externes en Python

Sur cette page

Pour la plupart des commandes externes courantes, utilisez subprocess.run(). Passez l’exécutable et ses arguments sous forme de liste afin que Python ne demande pas à un shell de les analyser. Définissez capture_output=True et text=True si vous avez besoin d’une sortie lisible, puis examinez stdout, stderr et returncode dans l’objet représentant le processus terminé. L’exemple ci-dessous lance Python lui-même : il ne dépend donc pas de la présence d’un utilitaire propre à un shell.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "print('Hello from Python')"],
    capture_output=True,
    text=True,
    check=True,
)
print(result.stdout, end="")
print("Return code:", result.returncode)
Hello from Python
Return code: 0

Une liste garde chaque argument distinct, y compris lorsqu’un argument contient des espaces. text=True décode les flux capturés en chaînes à l’aide de l’encodage texte de la plateforme ; sans cette option, stdout et stderr sont des octets. check=True déclenche une exception subprocess.CalledProcessError si la commande renvoie un statut non nul. Omettez cette option si vous voulez gérer vous-même le statut. La sortie capturée est indépendante du statut de la commande : celle-ci peut écrire dans l’un ou l’autre flux et tout de même se terminer avec un returncode non nul.

Utiliser os.system() pour exécuter une commande shell

os.system() transmet sa chaîne à un interpréteur de commandes (un shell sur les plateformes courantes) et renvoie le statut de cet interpréteur. La sortie standard et la sortie d’erreur de la commande restent normalement reliées au processus parent ; cet appel ne vous fournit donc pas de texte capturé. Cette interface historique convient à une commande shell simple lorsque le comportement du shell est voulu. Pour passer une liste d’arguments, capturer les flux ou gérer le statut de façon structurée, préférez subprocess.run().

Comme l’entrée est une syntaxe shell, ne construisez pas la chaîne en y insérant du texte non fiable. Les métacaractères du shell peuvent modifier les actions exécutées. L’interpréteur de commandes utilisé et l’encodage du statut varient selon la plateforme : ne supposez donc pas que la valeur renvoyée correspond toujours au code de sortie brut du programme enfant. Par exemple, la forme conceptuelle portable est os.system("some-command") ; choisissez une commande concrète et des règles de citation adaptées au système d’exploitation visé.

Utiliser os.popen() pour lire la sortie d’une commande

os.popen() ouvre un tube vers une commande exécutée par un shell et renvoie un objet de type fichier. Lisez le flux, puis fermez-le lorsque vous avez terminé ; close() peut également fournir le statut de la commande. Cette interface historique convient à une interaction simple par tube, mais ne permet pas de gérer séparément stdout et stderr comme le fait subprocess.

La forme générale est, par exemple, pipe = os.popen(command), puis output = pipe.read() et status = pipe.close(). La chaîne de commande est interprétée par un shell : prenez les mêmes précautions qu’avec os.system() si elle contient des données non fiables. La valeur renvoyée par close() ne remplace pas la sortie capturée et sa représentation du statut peut dépendre de la plateforme. Pour du code nouveau qui a besoin à la fois de la sortie et d’un code de retour clair, préférez subprocess.run().

Utiliser subprocess.Popen() pour un contrôle plus fin du processus

subprocess.Popen() est le constructeur de la classe à utiliser lorsqu’un programme doit interagir avec un processus pendant son exécution. Pour lancer directement un programme, passez une liste d’arguments. Définissez stdout=subprocess.PIPE ou stderr=subprocess.PIPE uniquement si vous prévoyez de lire ces flux. Appelez communicate() pour récupérer les tubes configurés et attendre la fin du processus, ou appelez wait() si aucune sortie acheminée par un tube ne doit être récupérée.

Lire manuellement un tube pendant que le processus enfant écrit abondamment dans un autre peut remplir un tampon du système d’exploitation et bloquer les processus. communicate() est généralement la méthode à privilégier pour récupérer les deux flux ensemble ; elle renvoie des octets, sauf si le mode texte est activé. Pour une sortie volumineuse ou en continu, traitez les flux de manière réfléchie au lieu de tout garder en mémoire. Si vous avez seulement besoin d’attendre la fin du processus et d’examiner son résultat, subprocess.run() est plus simple.

Utiliser subprocess.call() pour lancer une commande et attendre sa fin

subprocess.call() exécute une commande, attend qu’elle se termine et renvoie son statut. Fournissez une liste, par exemple subprocess.call(["program", "--version"]), pour éviter l’interprétation par un shell. Cette fonction utilitaire ne capture pas la sortie par défaut ; les flux du processus enfant sont hérités. Utilisez subprocess.run() si vous avez besoin de capturer les flux, de décoder le texte ou d’accéder aux champs de CompletedProcess. call() reste utile dans du code existant qui ne nécessite qu’un statut synchrone, mais le plus souvent, le code nouveau bénéficie de l’interface plus claire de run().

Un statut égal à zéro indique généralement une réussite, tandis qu’un statut non nul signale que la commande a rencontré un problème. La signification des valeurs non nulles dépend du programme appelé, et les conventions de statut peuvent varier selon les plateformes. Si vous voulez qu’un statut non nul soit traité comme une erreur, subprocess.run(..., check=True) déclenche CalledProcessError ; sinon, examinez returncode et décidez de la suite à donner dans votre application.

Utiliser subprocess.run() pour la plupart des commandes externes

Pour les tâches courantes, subprocess.run() attend la fin de l’exécution et renvoie un objet CompletedProcess. Avec capture_output=True, le résultat contient stdout et stderr ; avec text=True, ces valeurs sont des chaînes. L’exemple affiche la sortie standard et le code de retour, tandis que la sortie d’erreur reste accessible dans result.stderr. Si le programme écrit sur la sortie d’erreur, son texte n’apparaîtra pas dans result.stdout.

Privilégiez les listes d’arguments et conservez shell=False, la valeur par défaut, pour lancer directement un programme. Ainsi, les métacaractères du shell présents dans un argument ne sont pas interprétés comme de la syntaxe shell, même si le programme cible peut toujours présenter des risques liés à ses propres entrées et au traitement de ses options. N’utilisez shell=True que si vous avez besoin de fonctions du shell, comme les pipelines ou la redirection ; dans ce cas, gardez la commande shell fixe ou construisez-la avec des règles de citation adaptées à la plateforme. Une liste d’arguments est le choix portable par défaut, mais les noms des exécutables et les options de ligne de commande varient tout de même selon les systèmes d’exploitation.

Lorsqu’une commande échoue, choisissez comment traiter le résultat : utilisez check=True pour déclencher CalledProcessError, ou laissez cette option à False et prenez une décision en fonction de result.returncode. Si l’exécutable est introuvable ou si le processus ne peut pas démarrer, une erreur du système d’exploitation est déclenchée avant qu’un résultat de processus terminé existe. Ne déduisez pas la réussite du seul texte affiché : examinez le statut et, si nécessaire, les deux flux.

Conclusion

Utilisez subprocess.run() pour la plupart des commandes externes : cette interface garde les arguments distincts, attend la fin du processus et fournit un résultat contenant le statut ainsi que les flux éventuellement capturés. Utilisez subprocess.Popen() si vous avez besoin d’interagir avec le processus pendant son exécution. subprocess.call() est une fonction utilitaire synchrone qui ne fournit que le statut. os.system() et os.popen() sont des interfaces historiques fondées sur un shell ; choisissez-les uniquement si leur comportement convient à la tâche. Veillez à ce que les entrées transmises au shell soient fiables, ne capturez que les flux nécessaires et tenez compte des différences entre plateformes concernant les noms d’exécutables et les conventions de statut.