Was ist ein Unterprozess in Python? [5 Anwendungsbeispiele]

Veröffentlicht: 2021-05-23

Subprozesse ermöglichen Ihnen eine völlig neue Interaktion mit dem Betriebssystem.

Unser Computer führt die ganze Zeit Unterprozesse aus. Tatsächlich führen Sie bereits durch das Lesen dieses Artikels viele Prozesse wie einen Netzwerkmanager oder den Internetbrowser selbst aus.

Das Coole daran ist, dass jede Aktion, die wir auf unserem Computer ausführen, das Aufrufen eines Unterprozesses beinhaltet. Das gilt auch dann, wenn wir in Python ein einfaches „Hallo Welt“ -Skript schreiben.

Das Konzept des Unterprozesses mag unklar erscheinen, selbst wenn Sie schon eine Weile Programmieren lernen. Dieser Artikel befasst sich eingehend mit dem Hauptkonzept des Unterprozesses und der Verwendung der Python-Unterprozess-Standardbibliothek.

Am Ende dieses Tutorials werden Sie:

  • Verstehen Sie das Konzept des Teilprozesses
  • Die Grundlagen der Python-Subprozessbibliothek erlernt haben
  • Üben Sie Ihre Python-Kenntnisse mit nützlichen Beispielen

Lass uns darauf eingehen

Das Konzept des Teilprozesses

Im Allgemeinen ist ein Unterprozess ein Computerprozess, der von einem anderen Prozess erstellt wird.

Wir können uns einen Unterprozess als Baum vorstellen, in dem hinter jedem Elternprozess Kindprozesse laufen. Ich weiß, dass dies ziemlich verwirrend sein kann, aber sehen wir es mit einer einfachen Grafik.

Es gibt verschiedene Möglichkeiten, den Prozess auf unserem Computer zu visualisieren. Unter UNIX (Linux & MAC) haben wir beispielsweise htop, einen interaktiven Prozessbetrachter.

Htop-Prozessanzeige

Der Baummodus ist das nützlichste Werkzeug, um einen Blick auf die laufenden Unterprozesse zu werfen. Wir können es mit F5 aktivieren.

Wenn wir uns den Befehlsbereich genau ansehen, können wir die Struktur der Prozesse erkennen, die auf unserem Computer laufen.

Htop-Prozessstruktur
Alles beginnt mit /sbin/init , dem Befehl, der jeden Prozess auf unserem Computer startet. Von diesem Punkt aus können wir den Beginn anderer Prozesse wie xfce4-screenshoter und das xfce4-terminal sehen (was zu noch mehr Unterprozessen führt)

Wenn wir uns Windows ansehen, haben wir den mythischen Task-Manager, der nützlich ist, wenn Sie diese abstürzenden Programme auf unserem Computer beenden.

Windows-Task-Manager

Jetzt haben wir ein glasklares Konzept. Sehen wir uns an, wie wir Unterprozesse in Python implementieren können.

Unterprozesse in Python

Ein Unterprozess in Python ist eine Aufgabe, die ein Python-Skript an das Betriebssystem (OS) delegiert.

Die Subprozessbibliothek ermöglicht es uns, Subprozesse direkt aus Python heraus auszuführen und zu verwalten. Dazu gehört die Arbeit mit der Standardeingabe stdin , der Standardausgabe stdout und den Rückgabecodes.

Wir müssen es nicht mit PIP installieren, da es Teil der Python-Standardbibliothek ist.

Daher können wir mit der Verwendung von Unterprozessen in Python beginnen, indem wir einfach das Modul importieren.

 import subprocess # Using the module ....

Hinweis: Um diesem Artikel folgen zu können, benötigen Sie Python 3.5 +

Um zu überprüfen, welche Python-Version Sie derzeit haben, führen Sie einfach aus.

 ❯ python --version Python 3.9.5 # My result

Falls die Python-Version, die Sie erhalten, 2.x ist, können Sie den folgenden Befehl verwenden

 python3 --version

Um mit dem Thema fortzufahren, besteht die Hauptidee hinter der Subprozessbibliothek darin, mit dem Betriebssystem interagieren zu können, indem alle gewünschten Befehle direkt vom Python-Interpreter ausgeführt werden.

Das bedeutet, dass wir tun können, was wir wollen, solange unser Betriebssystem es uns erlaubt (und solange Sie Ihr Root-Dateisystem nicht entfernen).

Sehen wir uns an, wie Sie es verwenden, indem Sie ein einfaches Skript erstellen, das die Dateien des aktuellen Verzeichnisses auflistet.

Erster Teilprozess Antrag

Zuerst erstellen wir eine Datei list_dir.py . Dies wird die Datei sein, in der wir experimentieren werden, um Dateien aufzulisten.

 touch list_dir.py

Jetzt öffnen wir diese Datei und verwenden den folgenden Code.

 import subprocess subprocess.run('ls')

Zuerst importieren wir das Unterprozessmodul und verwenden dann die ausgeführte Funktion run , den Befehl, den wir als Argument übergeben.

Diese Funktion wurde in Python 3.5 als benutzerfreundliche Verknüpfung zu subprocess.Popen eingeführt. Die Funktion subprocess.run ermöglicht es uns, einen Befehl auszuführen und darauf zu warten, dass er beendet wird, im Gegensatz zu Popen, wo wir die Option haben, die Kommunikation später aufzurufen.

Apropos Codeausgabe: ls ist ein UNIX-Befehl, der die Dateien des Verzeichnisses auflistet, in dem Sie sich befinden. Wenn Sie diesen Befehl ausführen, erhalten Sie daher eine Liste der Dateien, die im aktuellen Verzeichnis vorhanden sind.

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

Hinweis: Beachten Sie, dass Sie unter Windows andere Befehle verwenden müssen. Anstelle von „ls“ können Sie beispielsweise „dir“ verwenden.

Das mag zu einfach erscheinen, und Sie haben Recht. Sie möchten die gesamte Leistung, die Ihnen die Shell bietet, vollständig nutzen. Lassen Sie uns also lernen, wie man Argumente mit subprocess an die Shell übergibt.

Um beispielsweise auch die versteckten Dateien (die mit einem Punkt beginnen) aufzulisten und auch alle Metadaten der Dateien aufzulisten, schreiben wir den folgenden Code.

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

Wir führen diesen Befehl als String aus und verwenden das Argument shell . Das bedeutet, dass wir zu Beginn der Ausführung unseres Unterprozesses eine Shell aufrufen und das Befehlsargument direkt von der Shell interpretiert wird.

Die Verwendung von shell=True hat jedoch viele Nachteile, und das Schlimmste sind die möglichen Sicherheitslücken. Sie können sie in der offiziellen Dokumentation nachlesen.

Der beste Weg, um Befehle an die run-Funktion zu übergeben, besteht darin, eine Liste zu verwenden, wobei lst[0] der aufzurufende Befehl ist (in diesem Fall ls) und lst[n] die Argumente dieses Befehls sind.

Wenn wir dies tun, sieht unser Code so aus.

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

Wenn wir die Standardausgabe eines Unterprozesses in einer Variablen speichern möchten, können wir dies tun, indem wir das Argument capture_output auf true setzen.

 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'

Um auf die Ausgabe eines Prozesses zuzugreifen, verwenden wir das Instanzattribut stdout .

In diesem Fall möchten wir die Ausgabe als String anstelle von Bytes speichern und können dies tun, indem wir das Textargument auf true setzen.

 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

Perfekt, jetzt, da wir die Grundlagen der Subprozessbibliothek kennen , ist es an der Zeit, zu einigen Anwendungsbeispielen überzugehen.

Verwendungsbeispiele für Unterprozesse in Python

In diesem Abschnitt werden wir einige praktische Anwendungen der Subprozessbibliothek überprüfen. Sie können alle in diesem Github-Repository überprüfen.

Programmprüfer

Eine der Hauptanwendungen dieser Bibliothek ist die Möglichkeit, einfache Betriebssystemoperationen durchzuführen.

Zum Beispiel ein einfaches Skript, das überprüft, ob ein Programm installiert ist. Unter Linux können wir tun dies mit dem dem Befehl.

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

Hinweis: Wenn ein Befehl unter UNIX erfolgreich ist, ist sein Statuscode 0. Andernfalls ist während der Ausführung etwas schief gelaufen

Da wir das Argument shell=True nicht verwenden, können wir die Benutzereingaben sicher entgegennehmen. Außerdem können wir überprüfen, ob die Eingabe ein gültiges Programm mit einem Regex-Muster ist.

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

In diesem Fall erhalten wir die Programme vom Benutzer und verwenden einen Regex-Ausdruck, der bestätigt, dass die Programmzeichenfolge nur Buchstaben und Ziffern enthält. Wir überprüfen die Existenz jedes Programms mit einer for-Schleife.

Einfaches Grep in Python

Ihr Freund Tom hat eine Liste mit Mustern in einer Textdatei und einer weiteren großen Datei, in der er die Anzahl der Übereinstimmungen für jedes Muster abrufen möchte. Er verbrachte Stunden damit, den grep-Befehl für jedes Muster auszuführen.

Glücklicherweise wissen Sie, wie Sie dieses Problem mit Python lösen können, und helfen ihm, diese Aufgabe in wenigen Sekunden zu erledigen.

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

Wenn wir uns diese Datei ansehen, definieren wir zwei Variablen, die die Dateinamen sind, mit denen wir arbeiten möchten. Dann öffnen wir die Datei, die alle Muster enthält, und durchlaufen sie. Als nächstes rufen wir einen Unterprozess auf, der einen grep-Befehl mit dem Flag „-c“ ausführt (bedeutet Anzahl) und bestimmen die Ausgabe der Übereinstimmung mit einer Bedingung.

Wenn Sie diese Datei ausführen (denken Sie daran, dass Sie die Textdateien aus dem Github-Repository herunterladen können)

Richten Sie eine virtuelle Umgebung mit Unterprozess ein

Eines der coolsten Dinge, die Sie mit Python tun können, ist die Prozessautomatisierung. Diese Art von Skript kann Ihnen Stunden an Zeit pro Woche sparen.

Zum Beispiel erstellen wir ein Setup-Skript, das eine virtuelle Umgebung für uns erstellt und versucht, eine Datei Requirements.txt im aktuellen Verzeichnis zu finden, um alle Abhängigkeiten zu installieren.

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

In diesem Fall verwenden wir mehrere Prozesse und analysieren die Daten, die wir in unserem Python-Skript benötigen. Wir verwenden auch die pathlib-Bibliothek, die es uns ermöglicht, herauszufinden, ob die Datei Requirements.txt existiert.

Wenn Sie die Python-Datei ausführen, erhalten Sie einige nützliche Meldungen darüber, was mit dem Betriebssystem passiert.

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

Beachten Sie, dass wir die Ausgabe aus dem Installationsprozess erhalten, da wir die Standardausgabe nicht an eine Variable umleiten.

Führen Sie eine andere Programmiersprache aus

Wir können andere Programmiersprachen mit Python ausführen und die Ausgabe aus diesen Dateien abrufen. Dies ist möglich, da die Teilprozesse direkt mit dem operativen System interagieren.

Lassen Sie uns zum Beispiel ein Hello-World-Programm in C++ und Java erstellen. Um die folgende Datei auszuführen, müssen Sie C++- und Java-Compiler installieren.

halloworld.cpp

 #include <iostream> int main(){ std::cout << "This is a hello world in C++" << std::endl; return 0; }


halloworld.java

 class HelloWorld{ public static void main(String args[]){ System.out.println("This is a hello world in Java"); } }


Ich weiß, dass dies im Vergleich zu einem einfachen Python-Einzeiler eine Menge Code zu sein scheint, aber dies dient nur zu Testzwecken.

Wir werden ein Python-Skript erstellen, das alle C++- und Java-Dateien in einem Verzeichnis ausführt. Um dies zu tun, möchten wir zuerst eine Liste von Dateien abhängig von der Dateierweiterung erhalten, und glob ermöglicht es uns, dies einfach zu tun!

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

Danach können wir mit der Verwendung von Unterprozessen beginnen, um jeden Dateityp auszuführen.

 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)

Der Trick besteht darin , die String - Funktion Streifen zu verwenden , um die Ausgabe zu ändern und nur das bekommen , was wir brauchen.

Hinweis: Seien Sie vorsichtig, wenn Sie große Java- oder C++-Dateien ausführen, da wir ihre Ausgabe in den Speicher laden und dies zu einem Speicherleck führen könnte.

Externe Programme öffnen

Wir können andere Programme ausführen, indem wir einfach den Speicherort ihrer Binärdateien über einen Unterprozess aufrufen.

Probieren wir es aus, indem wir brave , meinen bevorzugten Webbrowser, öffnen.

 import subprocess subprocess.run('brave')

Dadurch wird eine Browserinstanz oder nur ein weiterer Tab geöffnet, wenn Sie den Browser bereits ausgeführt haben.

Geöffneter Browser

Wie bei jedem anderen Programm, das Flags akzeptiert, können wir sie verwenden, um das gewünschte Verhalten zu erzeugen.

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

Inkognito-Flagge

Um zusammenzufassen

Ein Unterprozess ist ein Computerprozess, der von einem anderen Prozess erstellt wird. Wir können die Prozesse, die auf unserem Computer ausgeführt werden, mit Tools wie htop und dem Task-Manager überprüfen.

Python hat eine eigene Bibliothek, um mit Unterprozessen zu arbeiten. Derzeit bietet uns die Run- Funktion eine einfache Schnittstelle zum Erstellen und Verwalten von Teilprozessen.

Wir können mit ihnen jede Art von Anwendung erstellen, da wir direkt mit dem Betriebssystem interagieren.

Denken Sie abschließend daran, dass der beste Weg zum Lernen darin besteht, etwas zu erstellen, das Sie verwenden möchten.