Hva er en underprosess i Python? [5 Usage Examples]

Underprosesser lar deg samhandle på et helt nytt nivå med operativsystemet.

Datamaskinen vår kjører underprosesser hele tiden. Faktisk, bare ved å lese denne artikkelen, kjører du mange prosesser som en nettverksadministrator eller selve nettleseren.

Det kule med dette er at enhver handling vi gjør på datamaskinen vår innebærer å påkalle en underprosess. Det forblir sant selv om vi skriver et enkelt «hallo verden»-skript i python.

Konseptet med delprosessen kan virke uklart selv om du har lært programmering en stund. Denne artikkelen vil ta en dyp titt på hovedkonseptet til underprosessen, og hvordan du bruker Python underprosess standardbibliotek.

Ved slutten av denne opplæringen vil du:

  • Forstå begrepet delprosess
  • Har lært det grunnleggende om Python-underprosessbiblioteket
  • Øvde Python-ferdighetene dine med nyttige eksempler

La oss komme inn i det

Konseptet med delprosess

Grovt sagt er en delprosess en dataprosess opprettet av en annen prosess.

Vi kan tenke på en underprosess som et tre, der hver overordnede prosess har underordnede prosesser bak seg. Jeg vet at dette kan være ganske forvirrende, men la oss se det med en enkel grafikk.

Det er flere måter vi kan visualisere prosessen som kjører på datamaskinen vår. For eksempel, i UNIX (Linux & MAC) har vi htop, som er en interaktiv prosessviser.

Tremodusen er det mest nyttige verktøyet for å ta en titt på de kjørende underprosessene. Vi kan aktivere den med F5.

Hvis vi ser nøye på kommandodelen, kan vi legge merke til strukturen til prosessene som kjører på datamaskinen vår.

Det hele begynner med /sbin/init som er kommandoen som starter hver prosess på datamaskinen vår. Fra det tidspunktet kan vi se begynnelsen på andre prosesser som xfce4-skjermdumper og xfce4-terminalen (som bidrar til enda mer underprosess)

Når vi tar en titt på Windows, har vi det mytiske oppgavebehandling som er nyttige når du dreper de krasj programmene på maskinen vår.

Nå har vi et krystallklart konsept. La oss se hvordan vi kan implementere delprosesser i Python.

Underprosesser i Python

En underprosess i Python er en oppgave som et python-skript delegerer til operativsystemet (OS).

Underprosessbiblioteket lar oss utføre og administrere underprosesser direkte fra Python. Det innebærer å jobbe med standard input stdin, standard output stdout og returkoder.

Vi trenger ikke å installere det med PIP, siden det er en del av Python standard bibliotek.

Derfor kan vi begynne å bruke underprosesser i python bare ved å importere modulen.

import subprocess

# Using the module ....

Merk: For å følge med på denne artikkelen bør du ha Python 3.5+

For å sjekke python-versjonen du har for øyeblikket, bare kjør.

❯ python --version
Python 3.9.5 # My result

I tilfelle Python-versjonen du får er 2.x, kan du bruke følgende kommando

python3 --version

Fortsetter med emnet, er hovedideen bak underprosessbiblioteket å kunne samhandle med OS ved å utføre hvilke kommandoer vi ønsker, direkte fra Python-tolken.

Det betyr at vi kan gjøre hva vi vil, så lenge operativsystemet vårt tillater oss (og så lenge du ikke fjerner rotfilsystemet 😅).

  10 DKIM Record Generatorer å bruke

La oss se hvordan du bruker det ved å lage et enkelt skript som viser filene til gjeldende katalog.

Første delprosesssøknad

La oss først lage en fil list_dir.py. Dette vil være filen der vi skal eksperimentere med å liste filer.

touch list_dir.py

La oss nå åpne den filen og bruke følgende kode.

import subprocess 

subprocess.run('ls')

Først importerer vi underprosessmodulen, og bruker deretter funksjonen run som kjører, kommandoen vi sender som et argument.

Denne funksjonen ble introdusert i Python 3.5, som en vennlig snarvei til delprosess. Åpne. Subprocess.run-funksjonen lar oss kjøre en kommando og vente til den er ferdig, i motsetning til Popen hvor vi har muligheten til å ringe kommunisere senere.

Når vi snakker om kodeutgangen, er ls en UNIX-kommando som viser filene i katalogen du er i. Derfor, hvis du kjører denne kommandoen, vil du få en liste over filene som finnes i den gjeldende katalogen.

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

Merk: Ta hensyn til at hvis du er i Windows, må du bruke forskjellige kommandoer. For eksempel i stedet for å bruke «ls» kan du bruke «dir»

Dette kan virke for enkelt, og du har rett. Du vil ha en full tilnærming til all kraften skallet gir deg. Så la oss lære hvordan du sender argumenter til skallet med underprosessen.

For for eksempel å liste også de skjulte filene (de som starter med en prikk), og også liste alle metadataene til filene, skriver vi følgende kode.

import subprocess

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

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

Vi kjører denne kommandoen som en streng og bruker argumentskallet. Det betyr at vi påkaller et skall ved starten av utførelsen av underprosessen vår, og kommandoargumentet tolkes direkte av skallet.

Brukskallet=True har imidlertid mange ulemper, og det verste er mulige sikkerhetslekkasjer. Du kan lese om dem i offisiell dokumentasjon.

Den beste måten å sende kommandoer til kjørefunksjonen er å bruke en liste der lst[0] er kommandoen for å ringe (ls i dette tilfellet) og lst[n] er argumentene for den kommandoen.

Hvis vi gjør det, vil koden vår se slik ut.

import subprocess

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

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

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

Hvis vi ønsker å lagre standardutgangen til en delprosess i en variabel, kan vi gjøre det ved å sette argumentet capture_output til 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'

For å få tilgang til utdataene fra en prosess bruker vi instansattributtet stdout.

I dette tilfellet ønsker vi å lagre utdataene som en streng, i stedet for bytes, og vi kan gjøre det ved å sette tekstargumentet som sant.

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, nå som vi vet det grunnleggende om underprosessbiblioteket, er det på tide å gå videre til noen brukseksempler.

  Få detaljert informasjon om tilgangspunkter og tilkoblede enheter

Bruk Eksempler på delprosesser i Python

I denne delen skal vi gjennomgå noen praktiske bruksområder for underprosessbiblioteket. Du kan sjekke alle i denne Github-depot.

Programsjekker

En av hovedbrukene til dette biblioteket er muligheten til å lage enkle OS-operasjoner.

For eksempel et enkelt skript som sjekker om et program er installert. I Linux kan vi gjøre dette med hvilken kommando.

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

Merk: I UNIX når en kommando er vellykket er statuskoden 0. Ellers gikk noe galt under utførelsen

Siden vi ikke bruker shell=True-argumentet, kan vi ta brukerinndata på en sikker måte. Vi kan også sjekke om inngangen er et gyldig program med et regex-mønster.

import subprocess

import re

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

secure_pattern = 'sun'

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

I dette tilfellet henter vi programmene fra brukeren og bruker et regulært uttrykk som bekrefter at programstrengen bare inneholder bokstaver og sifre. Vi sjekker eksistensen av hvert program med en for en loop.

Enkel Grep i Python

Din venn Tom har en liste over mønstre i en tekstfil og en annen stor fil der han ønsker å få antall treff for hvert mønster. Han ville bruke timer på å kjøre grep-kommandoen for hvert mønster.

Heldigvis vet du hvordan du løser dette problemet med Python, og du vil hjelpe ham med å utføre denne oppgaven på få sekunder.

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

Ved å ta en titt på denne filen definerer vi to variabler som er filnavnene vi ønsker å jobbe med. Så åpner vi filen som inneholder alle mønstrene og itererer over dem. Deretter kaller vi en underprosess som kjører en grep-kommando med «-c»-flagget (betyr teller) og bestemmer resultatet av samsvaret med en betinget.

Hvis du kjører denne filen (husk at du kan laste ned tekstfilene fra Github repo)

Sett opp en virtualenv med underprosess

En av de kuleste tingene du kan gjøre med Python er prosessautomatisering. Denne typen skript kan spare deg for timer med tid per uke.

For eksempel skal vi lage et oppsettskript som lager et virtuelt miljø for oss og prøver å finne en requirements.txt-fil i gjeldende katalog for å installere alle avhengighetene.

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

  ChooseMyPC hjelper deg med å finne deler for å bygge din budsjett-PC

I dette tilfellet bruker vi flere prosesser og analyserer dataene vi trenger i python-skriptet vårt. Vi bruker også stilib bibliotek som lar oss finne ut om filen requirements.txt eksisterer.

Hvis du kjører python-filen, får du noen nyttige meldinger om hva som skjer med operativsystemet.

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

Merk at vi får utdata fra installasjonsprosessen fordi vi ikke omdirigerer standardutdata til en variabel.

Kjør et annet programmeringsspråk

Vi kan kjøre andre programmeringsspråk med python og få utdata fra disse filene. Dette er mulig fordi delprosessene samhandler direkte med det operative systemet.

La oss for eksempel lage et hello world-program i C++ og Java. For å kjøre følgende fil, må du installere C++ og Java kompilatorer.

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

Jeg vet at dette virker mye kode sammenlignet med en enkel Python one-liner, men dette er bare for testformål.

Vi skal lage et Python-skript som kjører alle C++- og Java-filene i en katalog. For å gjøre dette først ønsker vi å få en liste over filer avhengig av filtypen, og glob lar oss gjøre det enkelt!

from glob import glob

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

cpp_files = glob('*.cpp')

Etter det kan vi begynne å bruke underprosesser for å utføre hver type fil.

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)

Et lite triks er å bruke strengfunksjonsstripen for å endre utdataene og bare få det vi trenger.

Merk: Vær forsiktig med å kjøre store Java- eller C++-filer siden vi laster utdataene deres i minnet og det kan føre til en minnelekkasje.

Åpne eksterne programmer

Vi er i stand til å kjøre andre programmer bare ved å kalle deres binære plassering gjennom en underprosess.

La oss prøve det ved å åpne brave, min foretrukne nettleser.

import subprocess

subprocess.run('brave')

Dette vil åpne en nettleserforekomst, eller bare en annen fane hvis du allerede har kjørt nettleseren.

Som med alle andre programmer som aksepterer flagg, kan vi bruke dem til å produsere ønsket oppførsel.

import subprocess

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

Å oppsummere

En delprosess er en dataprosess opprettet av en annen prosess. Vi kan sjekke prosessene datamaskinen vår kjører med verktøy som htop og oppgavebehandling.

Python har sitt eget bibliotek for å jobbe med underprosesser. For øyeblikket gir kjørefunksjonen oss et enkelt grensesnitt for å lage og administrere delprosesser.

Vi kan lage alle typer applikasjoner med dem fordi vi samhandler direkte med operativsystemet.

Til slutt, husk at den beste måten å lære på er å lage noe du vil bruke.