Co to jest podproces w Pythonie? [5 przykładów użycia]
Opublikowany: 2021-05-23Podprocesy pozwalają na interakcję na zupełnie nowym poziomie z Systemem Operacyjnym.
Nasz komputer cały czas uruchamia podprocesy. W rzeczywistości, po prostu czytając ten artykuł, uruchamiasz wiele procesów, takich jak menedżer sieci lub sama przeglądarka internetowa.
Fajną rzeczą w tym jest to, że każda czynność, którą wykonujemy na naszym komputerze, wymaga wywołania podprocesu. To pozostaje prawdą, nawet jeśli piszemy prosty skrypt „hello world” w Pythonie.
Pojęcie podprocesu może wydawać się niejasne, nawet jeśli od jakiegoś czasu uczysz się programowania. W tym artykule przyjrzymy się bliżej głównej koncepcji podprocesu oraz sposobowi korzystania ze standardowej biblioteki podprocesów Pythona.
Pod koniec tego samouczka:
- Zrozum pojęcie podprocesu
- Nauczyłem się podstaw biblioteki podprocesów Pythona
- Ćwicz swoje umiejętności Pythona na przydatnych przykładach
Przejdźmy do tego
Pojęcie podprocesu
Mówiąc ogólnie, podproces to proces komputerowy stworzony przez inny proces.
Możemy myśleć o podprocesie jako o drzewie, w którym za każdym procesem nadrzędnym działają procesy potomne. Wiem, że może to być dość mylące, ale spójrzmy na prostą grafikę.

Istnieje kilka sposobów na wizualizację procesu uruchomionego na naszym komputerze. Na przykład w systemie UNIX (Linux i MAC) mamy htop, który jest interaktywną przeglądarką procesów.

Tryb drzewa jest najbardziej użytecznym narzędziem do przyjrzenia się działającym podprocesom. Możemy go aktywować klawiszem F5 .
Jeśli przyjrzymy się uważnie sekcji poleceń, możemy zauważyć strukturę procesów uruchomionych na naszym komputerze.

Wszystko zaczyna się od /sbin/init, czyli polecenia uruchamiającego każdy proces na naszym komputerze. Od tego momentu możemy zobaczyć początek innych procesów, takich jak xfce4-screenshoter i xfce4-terminal (co prowadzi do jeszcze większej liczby podprocesów)
Patrząc na system Windows, mamy mitycznego menedżera zadań, który jest przydatny podczas zabijania tych programów, które ulegają awarii na naszym komputerze.

Teraz mamy krystalicznie czystą koncepcję. Zobaczmy, jak możemy zaimplementować podprocesy w Pythonie.
Podprocesy w Pythonie
Podproces w Pythonie to zadanie, które skrypt Pythona deleguje do systemu operacyjnego (OS).
Biblioteka podprocesów pozwala nam na wykonywanie i zarządzanie podprocesami bezpośrednio z Pythona. Wiąże się to z pracą ze standardowym wejściem stdin , standardowym wyjściem stdout i kodami powrotu.
Nie musimy go instalować z PIP, ponieważ jest częścią standardowej biblioteki Pythona.
Dlatego możemy zacząć korzystać z podprocesów w pythonie po prostu importując moduł.
import subprocess # Using the module ....Uwaga: Aby śledzić ten artykuł, powinieneś mieć Python 3.5 +
Aby sprawdzić aktualną wersję Pythona, po prostu uruchom.
❯ python --version Python 3.9.5 # My resultJeśli otrzymana wersja Pythona to 2.x, możesz użyć następującego polecenia
python3 --versionKontynuując temat, główną ideą stojącą za biblioteką podprocesów jest możliwość interakcji z systemem operacyjnym poprzez wykonywanie dowolnych poleceń, bezpośrednio z interpretera Pythona.
Oznacza to, że możemy robić, co chcemy, o ile pozwala nam na to nasz system operacyjny (i tak długo, jak nie usuniesz głównego systemu plików ).
Zobaczmy, jak z niego korzystać, tworząc prosty skrypt, który wyświetla listę plików bieżącego katalogu.
Pierwsza aplikacja podprocesu
Najpierw utwórzmy plik list_dir.py . To będzie plik, w którym będziemy eksperymentować z listą plików.
touch list_dir.pyTeraz otwórzmy ten plik i użyjmy poniższego kodu.
import subprocess subprocess.run('ls')Najpierw importujemy moduł podprocesów, a następnie korzystając z uruchomionej funkcji, przekazujemy polecenie jako argument.
Ta funkcja została wprowadzona w Pythonie 3.5 jako przyjazny skrót do subprocess.Popen. Funkcja subprocess.run pozwala nam uruchomić polecenie i czekać na jego zakończenie, w przeciwieństwie do Popen, gdzie mamy możliwość późniejszego wywołania komunikacji.
Mówiąc o wyjściu kodu, ls jest poleceniem UNIX, które wyświetla listę plików katalogu, w którym się znajdujesz. Dlatego jeśli uruchomisz to polecenie, otrzymasz listę plików obecnych w bieżącym katalogu.
❯ python list_dir.py example.py LICENSE list_dir.py README.mdUwaga: weź pod uwagę, że jeśli pracujesz w systemie Windows, będziesz musiał użyć różnych poleceń. Na przykład zamiast „ls” możesz użyć „dir”
To może wydawać się zbyt proste i masz rację. Chcesz w pełni podejść do całej mocy, jaką daje powłoka. Nauczmy się więc przekazywać argumenty do powłoki za pomocą podprocesu.
Na przykład, aby wyświetlić także ukryte pliki (te, które zaczynają się od kropki), a także wyświetlić wszystkie metadane plików, piszemy następujący kod.
import subprocess # subprocess.run('ls') # Simple command subprocess.run('ls -la', shell=True)Uruchamiamy to polecenie jako ciąg znaków i używamy argumentu shell . Oznacza to, że wywołujemy powłokę na początku wykonywania naszego podprocesu, a argument polecenia jest interpretowany bezpośrednio przez powłokę.
Jednak użycie shell=True ma wiele wad, a najgorsze są możliwe przecieki bezpieczeństwa. Możesz o nich przeczytać w oficjalnej dokumentacji.
Najlepszym sposobem przekazywania poleceń do funkcji run jest użycie listy, gdzie lst[0] jest poleceniem do wywołania (w tym przypadku ls), a lst[n] jest argumentami tego polecenia.
Jeśli tak zrobimy, nasz kod będzie wyglądał tak.
import subprocess # subprocess.run('ls') # Simple command # subprocess.run('ls -la', shell=True) # Dangerous command subprocess.run(['ls', '-la'])Jeśli chcemy przechowywać standardowe wyjście podprocesu w zmiennej, możemy to zrobić, ustawiając argument capture_output na 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'Aby uzyskać dostęp do danych wyjściowych procesu, używamy atrybutu instancji stdout .
W tym przypadku chcemy przechowywać dane wyjściowe jako ciąg znaków, a nie bajty i możemy to zrobić, ustawiając argument tekstowy jako 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.mdIdealnie, teraz, gdy znamy już podstawy biblioteki podprocesów , czas przejść do kilku przykładów użycia.
Przykłady użycia podprocesu w Pythonie
W tej sekcji przyjrzymy się kilku praktycznym zastosowaniom biblioteki podprocesów. Możesz je wszystkie sprawdzić w tym repozytorium Github.
Kontroler programu
Jednym z głównych zastosowań tej biblioteki jest możliwość wykonywania prostych operacji systemu operacyjnego.
Na przykład prosty skrypt, który sprawdza, czy program jest zainstalowany. W Linuksie, możemy to zrobić z którego polecenia.
'''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)Uwaga: W systemie UNIX, gdy polecenie się powiedzie, jego kod statusu to 0. W przeciwnym razie coś poszło nie tak podczas wykonywania

Ponieważ nie używamy argumentu shell=True , możemy bezpiecznie przyjąć dane wejściowe użytkownika. Możemy również sprawdzić, czy dane wejściowe są poprawnym programem ze wzorcem 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')W tym przypadku pobieramy programy od użytkownika i używamy wyrażenia regularnego, które poświadcza, że ciąg programu zawiera tylko litery i cyfry. Sprawdzamy istnienie każdego programu za pomocą pętli for.
Prosty Grep w Pythonie
Twój przyjaciel Tom ma listę wzorców w pliku tekstowym i inny duży plik, w którym chce uzyskać liczbę dopasowań dla każdego wzorca. Spędzał godziny na uruchamianiu polecenia grep dla każdego wzorca.
Na szczęście wiesz, jak rozwiązać ten problem za pomocą Pythona i pomożesz mu wykonać to zadanie w kilka sekund.
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')Patrząc na ten plik, definiujemy dwie zmienne, które są nazwami plików, z którymi chcemy pracować. Następnie otwieramy plik zawierający wszystkie wzorce i powtarzamy je. Następnie wywołujemy podproces, który uruchamia polecenie grep z flagą „-c” (liczba oznacza) i określamy wynik dopasowania za pomocą warunku.
Jeśli uruchomisz ten plik (pamiętaj, że możesz pobrać pliki tekstowe z repozytorium Github)
Skonfiguruj wirtualne środowisko z podprocesem
Jedną z najfajniejszych rzeczy, które możesz zrobić w Pythonie, jest automatyzacja procesów. Ten rodzaj skryptu pozwala zaoszczędzić wiele godzin tygodniowo.
Na przykład, mamy zamiar utworzyć skrypt instalacyjny, który tworzy wirtualne środowisko dla nas i próbuje znaleźć plik requirements.txt w bieżącym katalogu, aby zainstalować wszystkie zależności.
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 ...")W tym przypadku używamy wielu procesów i analizujemy dane, których potrzebujemy w naszym skrypcie Pythona. Jesteśmy również przy użyciu biblioteki pathlib co pozwala nam zrozumieć to, czy plik requirements.txt istnieje.
Jeśli uruchomisz plik Pythona, otrzymasz przydatne komunikaty o tym, co dzieje się z systemem operacyjnym.
❯ 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"Zauważ, że otrzymujemy dane wyjściowe z procesu instalacji, ponieważ nie przekierowujemy standardowego wyjścia do zmiennej.
Uruchom inny język programowania
Możemy uruchomić inne języki programowania za pomocą Pythona i uzyskać dane wyjściowe z tych plików. Jest to możliwe, ponieważ podprocesy współdziałają bezpośrednio z systemem operacyjnym.
Na przykład stwórzmy program hello world w C++ i Javie. Aby wykonać poniższy plik, musisz zainstalować kompilatory C++ i 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"); } }
Wiem, że wygląda to na dużo kodu w porównaniu z prostym jednowierszowym językiem Pythona, ale to tylko do celów testowych.
Stworzymy skrypt Pythona, który uruchomi wszystkie pliki C++ i Java w katalogu. Aby to zrobić najpierw chcemy uzyskać listę plików w zależności od rozszerzenia pliku, a glob pozwala nam to zrobić łatwo!
from glob import glob # Gets files with each extension java_files = glob('*.java') cpp_files = glob('*.cpp')Następnie możemy zacząć używać podprocesów do wykonywania każdego typu pliku.
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)Jedna mała sztuczka polega na użyciu funkcji string strip do modyfikowania danych wyjściowych i uzyskiwania tylko tego, czego potrzebujemy.
Uwaga: Zachowaj ostrożność, aby uruchamiać duże pliki Java lub C++, ponieważ ładujemy ich dane wyjściowe do pamięci i może to spowodować wyciek pamięci.
Otwórz programy zewnętrzne
Jesteśmy w stanie uruchomić inne programy, po prostu wywołując lokalizację ich plików binarnych za pomocą podprocesu.
Wypróbujmy to, otwierając odważną , moją ulubioną przeglądarkę internetową.
import subprocess subprocess.run('brave')Spowoduje to otwarcie instancji przeglądarki lub po prostu kolejną kartę, jeśli masz już uruchomioną przeglądarkę.

Podobnie jak w przypadku każdego innego programu, który akceptuje flagi, możemy ich użyć do uzyskania pożądanego zachowania.
import subprocess subprocess.run(['brave', '--incognito']) 
Podsumowując
Podproces to proces komputerowy utworzony przez inny proces. Za pomocą narzędzi takich jak htop i menedżer zadań możemy sprawdzić procesy, które uruchamia nasz komputer.
Python posiada własną bibliotekę do pracy z podprocesami. Obecnie funkcja run daje nam prosty interfejs do tworzenia i zarządzania podprocesami.
Możemy za ich pomocą tworzyć dowolny rodzaj aplikacji, ponieważ wchodzimy w bezpośrednią interakcję z systemem operacyjnym.
Na koniec pamiętaj, że najlepszym sposobem na naukę jest stworzenie czegoś, z czego chciałbyś korzystać.
