HOWTO · Python
Rufen Sie das externe Programm in Python auf
Dieses Tutorial zeigt, wie externe Programme in Python ausgeführt werden
Auf dieser Seite
Verwenden Sie subprocess.run() für die meisten gewöhnlichen externen Befehle. Übergeben Sie das Programm und seine Argumente als Liste, damit Python sie nicht von einer Shell auswerten lässt. Setzen Sie capture_output=True und text=True, wenn Sie lesbare Ausgaben benötigen, und prüfen Sie anschließend stdout, stderr und returncode im Ergebnisobjekt des abgeschlossenen Prozesses. Das Beispiel startet Python selbst und setzt daher kein installiertes Shell-Hilfsprogramm voraus.
Führen Sie dieses Beispiel aus:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
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
Eine Liste hält die einzelnen Argumente getrennt, auch wenn ein Argument Leerzeichen enthält. text=True dekodiert die erfassten Datenströme anhand der Textkodierung der Plattform in Zeichenketten; ohne diese Option sind stdout und stderr Bytes. Bei check=True führt ein von null verschiedener Befehlsstatus zu subprocess.CalledProcessError. Lassen Sie die Option weg, wenn Sie den Status selbst behandeln möchten. Erfasste Ausgabe und Befehlsstatus sind voneinander unabhängig: Ein Befehl kann in einen der beiden Datenströme schreiben und dennoch mit einem von null verschiedenen returncode enden.
os.system() zum Ausführen eines Shell-Befehls verwenden
os.system() führt seine Zeichenkette über einen Befehlsinterpreter aus (auf gängigen Plattformen eine Shell) und gibt den Status des Befehlsinterpreters zurück. Die Standardausgabe und der Standardfehler des Befehls bleiben normalerweise mit dem übergeordneten Prozess verbunden, daher liefert dieser Aufruf keinen erfassten Text. Für einen einfachen Shell-Befehl ist dies eine veraltete Möglichkeit, wenn das Shell-Verhalten beabsichtigt ist. Für eine Argumentliste, erfasste Datenströme oder eine strukturierte Statusbehandlung ist subprocess.run() vorzuziehen.
Da die Eingabe Shell-Syntax ist, sollten Sie die Zeichenkette nicht durch Einfügen nicht vertrauenswürdiger Texte zusammensetzen. Shell-Metazeichen können verändern, was ausgeführt wird. Der genaue Befehlsinterpreter und die Kodierung des Status unterscheiden sich je nach Plattform. Gehen Sie daher nicht davon aus, dass ein zurückgegebener Wert immer unverändert dem Exit-Code des Kindprozesses entspricht. Ein portabler Aufruf in seiner Grundform ist etwa os.system("some-command"); wählen Sie einen konkreten Befehl und passende Anführungsregeln für das Betriebssystem, auf dem er ausgeführt wird.
os.popen() zum Lesen der Befehlsausgabe verwenden
os.popen() öffnet eine Pipe zu einem Befehl, der über eine Shell ausgeführt wird, und gibt ein dateiähnliches Objekt zurück. Lesen Sie den Datenstrom und schließen Sie ihn anschließend; close() kann außerdem den Befehlsstatus liefern. Diese Schnittstelle ist eine veraltete Möglichkeit für einfache Interaktionen über Pipes und bietet nicht die getrennte Behandlung von stdout und stderr, die subprocess ermöglicht.
Ein mögliches Muster ist pipe = os.popen(command), gefolgt von output = pipe.read() und status = pipe.close(). Die Befehlszeichenkette wird von einer Shell interpretiert. Gehen Sie daher mit nicht vertrauenswürdigen Eingaben ebenso vorsichtig um wie bei os.system(). Der Rückgabewert von close() ersetzt nicht die erfasste Ausgabe, und seine Darstellung des Status kann von der Plattform abhängen. Für neuen Code, der sowohl die Ausgabe als auch einen eindeutigen Rückgabecode benötigt, ist subprocess.run() vorzuziehen.
subprocess.Popen() für eine Steuerung auf niedrigerer Ebene verwenden
subprocess.Popen() ist der Klassenkonstruktor für Programme, die mit einem Prozess interagieren müssen, während dieser läuft. Für die direkte Ausführung übergeben Sie eine Argumentliste. Setzen Sie stdout=subprocess.PIPE oder stderr=subprocess.PIPE nur, wenn Sie diese Datenströme auch lesen möchten. Rufen Sie communicate() auf, um die eingerichteten Pipes auszulesen und auf den Abschluss zu warten, oder verwenden Sie wait(), wenn keine gepufferten Ausgaben eingesammelt werden müssen.
Wenn Sie eine Pipe manuell lesen, während der Kindprozess viel in eine andere schreibt, kann sich ein Betriebssystempuffer füllen und beide Prozesse blockieren. communicate() ist die übliche Methode, beide Datenströme gemeinsam einzusammeln; ohne aktivierten Textmodus gibt die Methode Bytes zurück. Bei großen oder kontinuierlich anfallenden Ausgaben sollten Sie die Datenströme gezielt verarbeiten, statt alles im Speicher zu puffern. Wenn Sie nur warten und anschließend ein abgeschlossenes Ergebnis prüfen möchten, ist subprocess.run() einfacher.
subprocess.call() zum Ausführen eines Befehls und Warten verwenden
subprocess.call() führt einen Befehl aus, wartet auf dessen Abschluss und gibt seinen Status zurück. Übergeben Sie eine Liste wie subprocess.call(["program", "--version"]), um eine Auswertung durch die Shell zu vermeiden. Diese praktische Funktion erfasst die Ausgabe standardmäßig nicht; die Datenströme des Kindprozesses werden übernommen. Verwenden Sie subprocess.run(), wenn Sie erfasste Datenströme, Textdekodierung oder die Felder von CompletedProcess benötigen. call() ist weiterhin nützlich, wenn vorhandener Code nur synchron einen Status benötigt. Neuer Code profitiert jedoch meist von der übersichtlicheren Schnittstelle run().
Ein Status von null deutet gewöhnlich auf Erfolg hin, ein von null verschiedener Status darauf, dass der Befehl ein Problem gemeldet hat. Was bestimmte Werte ungleich null bedeuten, hängt vom aufgerufenen Programm ab; auch die Statuskonventionen können sich je nach Plattform unterscheiden. Soll ein Status ungleich null als Fehler behandelt werden, löst subprocess.run(..., check=True) eine CalledProcessError aus. Andernfalls prüfen Sie returncode und entscheiden, wie Ihre Anwendung darauf reagieren soll.
subprocess.run() für die meisten externen Befehle verwenden
Bei gewöhnlichen Aufgaben wartet subprocess.run() auf den Abschluss und gibt ein CompletedProcess zurück. Mit capture_output=True enthält das Ergebnis stdout und stderr; mit text=True sind diese Werte Zeichenketten. Das Beispiel gibt die Standardausgabe und den Rückgabecode aus; der Standardfehler bleibt unter result.stderr verfügbar. Schreibt das Programm auf den Standardfehler, erscheint diese Ausgabe nicht in result.stdout.
Verwenden Sie vorzugsweise Argumentlisten und lassen Sie shell=False, den Standardwert, für den direkten Programmaufruf eingestellt. Dadurch werden Shell-Metazeichen in einem Argument nicht als Shell-Syntax interpretiert. Das Zielprogramm kann jedoch weiterhin eigene Risiken bei der Verarbeitung von Eingaben und Optionen haben. Setzen Sie shell=True nur ein, wenn Shell-Funktionen wie Pipes oder Umleitungen erforderlich sind. Halten Sie den Shell-Befehl dann unverändert oder erstellen Sie ihn mit sorgfältiger, plattformgerechter Quoting-Behandlung. Eine Argumentliste ist die portable Standardeinstellung, doch Programmnamen und Befehlszeilenoptionen unterscheiden sich weiterhin zwischen Betriebssystemen.
Legen Sie bei einem fehlgeschlagenen Befehl fest, wie Sie das Ergebnis behandeln möchten: Mit check=True wird bei CalledProcessError abgebrochen; andernfalls können Sie anhand von result.returncode verzweigen. Ein fehlendes Programm oder ein anderer Fehler beim Prozessstart löst einen Betriebssystemfehler aus, bevor ein abgeschlossenes Ergebnis vorliegt. Leiten Sie den Erfolg nicht allein aus dem Ausgabetext ab: Prüfen Sie den Status und bei Bedarf beide Datenströme.
Fazit
Verwenden Sie subprocess.run() für die meisten externen Befehle: Die Argumente bleiben getrennt, der Aufruf wartet auf den Prozess und liefert ein Ergebnis mit Status sowie gegebenenfalls den erfassten Datenströmen. Nutzen Sie subprocess.Popen(), wenn Sie während der Laufzeit eine Steuerung auf niedrigerer Ebene benötigen. subprocess.call() ist eine kompakte synchrone Hilfsfunktion, die nur den Status zurückgibt. os.system() und os.popen() sind veraltete Shell-Schnittstellen; verwenden Sie sie nur, wenn ihr Verhalten zur Aufgabe passt. Übergeben Sie der Shell nur vertrauenswürdige Eingaben, erfassen Sie nur die benötigten Datenströme und berücksichtigen Sie Unterschiede bei Programmnamen und Statuskonventionen zwischen Plattformen.