Ce este un subproces în Python? [5 Usage Examples]

Subprocesele vă permit să interacționați la un nivel cu totul nou cu sistemul operativ.

Computerul nostru rulează subprocese tot timpul. De fapt, doar citind acest articol, rulezi o mulțime de procese, cum ar fi un manager de rețea sau browserul de internet însuși.

Lucrul tare despre asta este că orice acțiune pe care o facem pe computerul nostru implică invocarea unui subproces. Asta rămâne adevărat chiar dacă scriem un simplu script „hello world” în python.

Conceptul de subproces poate părea obscur chiar dacă ați învățat programare de ceva vreme. Acest articol va arunca o privire profundă asupra conceptului principal al subprocesului și cum să utilizați Python biblioteca standard de subprocese.

Până la sfârșitul acestui tutorial, veți:

  • Înțelegeți conceptul de subproces
  • Ați învățat elementele de bază ale bibliotecii de subprocese Python
  • Exersați-vă abilitățile Python cu exemple utile

Să intrăm în asta

Conceptul de subproces

În linii mari, un subproces este un proces computerizat creat printr-un alt proces.

Ne putem gândi la un subproces ca la un arbore, în care fiecare proces părinte are procese copil care rulează în spate. Știu că acest lucru poate fi destul de confuz, dar să vedem asta cu o grafică simplă.

Există mai multe moduri prin care putem vizualiza procesul care rulează pe computerul nostru. De exemplu, în UNIX (Linux și MAC) avem htop, care este un vizualizator interactiv de proces.

Modul arbore este cel mai util instrument pentru a arunca o privire asupra subproceselor care rulează. Îl putem activa cu F5.

Dacă ne uităm îndeaproape la secțiunea de comandă, putem observa structura proceselor care rulează pe computerul nostru.

Totul începe cu /sbin/init care este comanda care pornește fiecare proces pe computerul nostru. Din acel punct, putem vedea începutul altor procese, cum ar fi xfce4-screenshoter și xfce4-terminal (ceea ce duce la și mai mult subproces)

Aruncând o privire la Windows, avem miticul gestionar de sarcini care rezultă util atunci când ucideți acele programe care se blochează pe mașina noastră.

Acum avem un concept clar de cristal. Să vedem cum putem implementa subprocese în Python.

Subprocese în Python

Un subproces în Python este o sarcină pe care un script Python o delege sistemului de operare (OS).

Biblioteca de subprocese ne permite să executăm și să gestionăm subprocesele direct din Python. Aceasta implică lucrul cu standardul de intrare stdin, standardul de ieșire stdout și codurile de returnare.

Nu trebuie să-l instalăm cu PIP, deoarece face parte din Python bibliotecă standard.

Prin urmare, putem începe să folosim subprocese în python doar importând modulul.

import subprocess

# Using the module ....

Notă: Pentru a urma acest articol, ar trebui să aveți Python 3.5 +

Pentru a verifica versiunea python pe care o aveți în prezent, rulați.

❯ python --version
Python 3.9.5 # My result

În cazul în care versiunea Python pe care o obțineți este 2.x, puteți utiliza următoarea comandă

python3 --version

Continuând cu subiectul, ideea principală din spatele bibliotecii de subprocese este să putem interacționa cu sistemul de operare executând orice comenzi dorim, direct din interpretul Python.

  Puterea progreselor tehnologice asupra educației

Asta înseamnă că putem face tot ce vrem, atâta timp cât sistemul nostru de operare ne permite (și atâta timp cât nu eliminați sistemul de fișiere rădăcină 😅).

Să vedem cum să-l folosim creând un script simplu care listează fișierele directorului curent.

Primul subproces de aplicare

Mai întâi, să creăm un fișier list_dir.py. Acesta va fi fișierul în care vom experimenta fișierele de listă.

touch list_dir.py

Acum să deschidem acel fișier și să folosim următorul cod.

import subprocess 

subprocess.run('ls')

Mai întâi, importăm modulul de subproces și apoi utilizăm funcția run care rulează, comanda pe care o transmitem ca argument.

Această funcție a fost introdusă în Python 3.5, ca o comandă rapidă prietenoasă la subproces.Popen. Funcția subprocess.run ne permite să rulăm o comandă și să așteptăm ca aceasta să se termine, spre deosebire de Popen, unde avem opțiunea de a apela la comunicare mai târziu.

Vorbind despre rezultatul codului, ls este o comandă UNIX care listează fișierele directorului în care vă aflați. Prin urmare, dacă rulați această comandă, veți obține o listă a fișierelor prezente în directorul curent.

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

Notă: țineți cont de faptul că, dacă sunteți în Windows, va trebui să utilizați diferite comenzi. De exemplu, în loc să folosiți „ls” puteți folosi „dir”

Acest lucru poate părea prea simplu și ai dreptate. Vrei să abordezi toată puterea pe care ți-o aduce carcasa. Deci, să învățăm cum să transmitem argumente către shell cu subproces.

De exemplu, pentru a enumera și fișierele ascunse (cele care încep cu un punct) și, de asemenea, pentru a enumera toate metadatele fișierelor, scriem următorul cod.

import subprocess

# subprocess.run('ls')  # Simple command

subprocess.run('ls -la', shell=True)

Rulăm această comandă ca șir și utilizăm argumentul shell. Asta înseamnă că invocăm un shell la începutul execuției subprocesului nostru, iar argumentul comenzii este interpretat direct de shell.

Cu toate acestea, use shell=True are multe dezavantaje, iar cele mai rele sunt posibilele scurgeri de securitate. Puteți citi despre ele în documentație oficială.

Cel mai bun mod de a transmite comenzi la funcția de rulare este de a folosi o listă unde lst[0] este comanda de apelat (ls în acest caz) și lst[n] sunt argumentele acelei comenzi.

Dacă facem acest lucru, codul nostru va arăta astfel.

import subprocess

# subprocess.run('ls')  # Simple command

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

subprocess.run(['ls', '-la'])

Dacă dorim să stocăm ieșirea standard a unui subproces într-o variabilă, o putem face setând argumentul capture_output la true.

list_of_files = subprocess.run(['ls', '-la'], capture_output=True)

print(list_of_files.stdout)

❯ python list_dir.py 
b'total 36ndrwxr-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.pyndrwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .gitn-rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignoren-rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.pyn-rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSEn-rw-r--r-- 1 daniel daniel 216 may 20 22:12 list_dir.pyn-rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.mdn'

Pentru a accesa rezultatul unui proces, folosim atributul de instanță stdout.

În acest caz, dorim să stocăm rezultatul ca șir, în loc de octeți și putem face acest lucru setând argumentul text ca adevărat.

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

Perfect, acum că cunoaștem elementele de bază ale bibliotecii de subprocese, este timpul să trecem la câteva exemple de utilizare.

  Cum vă poate afecta căutarea inteligentă afacerea

Exemple de utilizare de subproces în Python

În această secțiune, vom trece în revistă câteva utilizări practice ale bibliotecii de subprocese. Le puteți verifica pe toate în aceasta Depozitul Github.

Verificator de programe

Una dintre principalele utilizări ale acestei biblioteci este capacitatea de a face operațiuni simple de sistem de operare.

De exemplu, un script simplu care verifică dacă este instalat un program. În Linux, putem face acest lucru cu comanda 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)

Notă: În UNIX, când o comandă are succes, codul său de stare este 0. În caz contrar, ceva a mers prost în timpul execuției

Deoarece nu folosim argumentul shell=True, putem prelua în siguranță intrarea utilizatorului. De asemenea, putem verifica dacă intrarea este un program valid cu un model regex.

import subprocess

import re

programs = input('Separe the programs with a space: ').split()

secure_pattern = 'mar'

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

În acest caz, primim programele de la utilizator și utilizăm o expresie regex care certifică că șirul programului include doar litere și cifre. Verificăm existența fiecărui program cu o buclă for.

Grep simplu în Python

Prietenul tău Tom are o listă de modele într-un fișier text și un alt fișier mare în care vrea să obțină numărul de potriviri pentru fiecare model. Ar petrece ore în șir rulând comanda grep pentru fiecare model.

Din fericire, știi cum să rezolvi această problemă cu Python și îl vei ajuta să îndeplinească această sarcină în câteva secunde.

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

Aruncând o privire la acest fișier, definim două variabile care sunt numele fișierelor cu care dorim să lucrăm. Apoi deschidem fișierul care conține toate modelele și repetăm ​​peste ele. Apoi, numim un subproces care rulează o comandă grep cu indicatorul „-c” (înseamnă număr) și determinăm rezultatul potrivirii cu o condițională.

Dacă rulați acest fișier (rețineți că puteți descărca fișierele text din fișierul Repoziție Github)

Configurați un virtualenv cu subproces

Unul dintre cele mai tari lucruri pe care le puteți face cu Python este automatizarea proceselor. Acest tip de script vă poate economisi ore de timp pe săptămână.

De exemplu, vom crea un script de configurare care creează un mediu virtual pentru noi și încearcă să găsească un fișier requirements.txt în directorul curent pentru a instala toate dependențele.

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

  Un scurt ghid pentru a vă ajuta biroul să rămână fără hârtie [7 Tools]

În acest caz, folosim mai multe procese și analizăm datele de care avem nevoie în scriptul nostru python. De asemenea, folosim calea lib bibliotecă care ne permite să ne dăm seama dacă fișierul requirements.txt există.

Dacă rulați fișierul Python, veți primi câteva mesaje utile despre ceea ce se întâmplă cu sistemul de operare.

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

Rețineți că obținem rezultatul din procesul de instalare, deoarece nu redirecționăm ieșirea standard către o variabilă.

Rulați un alt limbaj de programare

Putem rula alte limbaje de programare cu python și obținem rezultatul din acele fișiere. Acest lucru este posibil deoarece subprocesele interacționează direct cu sistemul operativ.

De exemplu, să creăm un program Hello World în C++ și Java. Pentru a executa următorul fișier, va trebui să instalați C++ și Java compilatoare.

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");  
    }  
}  

Știu că pare mult cod în comparație cu un simplu Python, dar acesta este doar în scopuri de testare.

Vom crea un script Python care rulează toate fișierele C++ și Java dintr-un director. Pentru a face acest lucru mai întâi dorim să obținem o listă de fișiere în funcție de extensia fișierului și glob ne permite să o facem cu ușurință!

from glob import glob

# Gets files with each extension
java_files = glob('*.java')

cpp_files = glob('*.cpp')

După aceea, putem începe să folosim subprocese pentru a executa fiecare tip de fișier.

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)

Un mic truc este să folosim banda funcției șir pentru a modifica rezultatul și pentru a obține doar ceea ce avem nevoie.

Notă: Aveți grijă să rulați fișiere Java sau C++ mari, deoarece încărcăm rezultatele lor în memorie, ceea ce ar putea produce o scurgere de memorie.

Deschideți programe externe

Putem rula alte programe doar apelând locația lor binare printr-un subproces.

Să încercăm deschizând brave, browserul meu web preferat.

import subprocess

subprocess.run('brave')

Aceasta va deschide o instanță de browser sau doar o altă filă dacă rulați deja browserul.

Ca și în cazul oricărui alt program care acceptă steaguri, le putem folosi pentru a produce comportamentul dorit.

import subprocess

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

În concluzie

Un subproces este un proces computerizat creat de un alt proces. Putem verifica procesele pe care le rulează computerul nostru cu instrumente precum htop și managerul de activități.

Python are propria bibliotecă pentru a lucra cu subprocese. În prezent, funcția de rulare ne oferă o interfață simplă pentru a crea și gestiona subprocese.

Putem crea orice fel de aplicație cu ei, deoarece interacționăm direct cu sistemul de operare.

În cele din urmă, amintiți-vă că cel mai bun mod de a învăța este să creați ceva pe care doriți să îl utilizați.