Какво е подпроцес в Python? [5 Usage Examples]

Подпроцесите ви позволяват да взаимодействате на напълно ново ниво с оперативната система.

Нашият компютър изпълнява подпроцеси през цялото време. Всъщност, само като прочетете тази статия, вие изпълнявате много процеси като мрежов мениджър или самия интернет браузър.

Страхотното в това е, че всяко действие, което правим на нашия компютър, включва извикване на подпроцес. Това остава вярно, дори ако пишем прост скрипт „здравей свят“ на python.

Концепцията за подпроцеса може да изглежда неясна, дори ако сте учили програмиране от известно време. Тази статия ще разгледа задълбочено основната концепция на подпроцеса и как да използвате Python стандартна библиотека на подпроцес.

До края на този урок вие ще:

  • Разберете концепцията за подпроцес
  • Научихте основите на библиотеката на подпроцесите на Python
  • Практикувате уменията си за Python с полезни примери

Нека влезем в него

Концепцията за подпроцес

Най-общо казано, подпроцесът е a компютърен процес създадени от друг процес.

Можем да мислим за подпроцес като дърво, в което всеки родителски процес има дъщерни процеси, работещи зад него. Знам, че това може да е доста объркващо, но нека го видим с проста графика.

Има няколко начина, по които можем да визуализираме процеса, който се изпълнява на нашия компютър. Например в UNIX (Linux & MAC) имаме htop, който е интерактивен преглед на процеси.

Дървовидният режим е най-полезният инструмент за разглеждане на изпълняваните подпроцеси. Можем да го активираме с F5.

Ако се вгледаме внимателно в командния раздел, можем да забележим структурата на процесите, изпълнявани на нашия компютър.

Всичко започва с /sbin/init което е командата, която стартира всеки процес на нашия компютър. От тази точка можем да видим началото на други процеси като xfce4-screenshoter и xfce4-терминал (което води до още повече подпроцеси)

Като погледнем Windows, имаме митичното Диспечер на задачите което води до полезно при убиване на тези сриващи се програми на нашата машина.

Сега имаме кристално ясна концепция. Нека видим как можем да внедрим подпроцеси в Python.

Подпроцеси в Python

Подпроцес в Python е задача, която скрипт на python делегира на операционната система (OS).

Библиотеката на подпроцесите ни позволява да изпълняваме и управляваме подпроцеси директно от Python. Това включва работа със стандартен вход stdin, стандартен изход stdout и кодове за връщане.

Не е нужно да го инсталираме с PIP, тъй като е част от Python стандартна библиотека.

Следователно можем да започнем да използваме подпроцеси в python просто като импортираме модула.

import subprocess

# Using the module ....

Забележка: За да следвате тази статия, трябва да имате Python 3.5 +

За да проверите версията на Python, която имате в момента, просто стартирайте.

❯ python --version
Python 3.9.5 # My result

В случай, че версията на Python, която получавате, е 2.x, можете да използвате следната команда

python3 --version

Продължавайки с темата, основната идея зад библиотеката на подпроцесите е да можем да взаимодействаме с операционната система, като изпълняваме всякакви команди, които искаме, директно от интерпретатора на Python.

Това означава, че можем да правим каквото си поискаме, стига нашата операционна система да ни позволява (и стига да не премахнете основната си файлова система 😅).

  9 най-добри Microsoft WSUS алтернативни инструменти за управление на корекции за SMB

Нека видим как да го използваме, като създадем прост скрипт, който изброява файловете в текущата директория.

Първо приложение на подпроцес

Първо, нека създадем файл list_dir.py. Това ще бъде файлът, в който ще експериментираме с изброяване на файлове.

touch list_dir.py

Сега нека отворим този файл и да използваме следния код.

import subprocess 

subprocess.run('ls')

Първо импортираме модула на подпроцеса и след това използваме функцията run, която се изпълнява, командата, която предаваме като аргумент.

Тази функция беше въведена в Python 3.5, като приятелски пряк път към подпроцес.Поп. Функцията subprocess.run ни позволява да изпълним команда и да изчакаме да завърши, за разлика от Popen, където имаме опцията да извикаме комуникация по-късно.

Говорейки за изходния код, ls е UNIX команда, която изброява файловете на директорията, в която се намирате. Следователно, ако изпълните тази команда, ще получите списък с файловете, налични в текущата директория.

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

Забележка: Имайте предвид, че ако сте в Windows, ще трябва да използвате различни команди. Например вместо да използвате „ls“, можете да използвате „dir“

Това може да изглежда твърде просто и сте прави. Искате да вземете пълен подход към цялата сила, която черупката ви носи. И така, нека научим как да предаваме аргументи на обвивката с подпроцес.

Например, за да изброим скритите файлове (тези, които започват с точка), както и всички метаданни на файловете, пишем следния код.

import subprocess

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

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

Изпълняваме тази команда като низ и използваме обвивката на аргумента. Това означава, че извикваме обвивка в началото на изпълнението на нашия подпроцес и командният аргумент се интерпретира директно от обвивката.

Използването shell=True обаче има много недостатъци, а най-лошите са възможните течове на сигурността. Можете да прочетете за тях в официална документация.

Най-добрият начин за предаване на команди към функцията за изпълнение е да използвате списък, където lst[0] е командата за извикване (ls в този случай) и lst[n] са аргументите на тази команда.

Ако го направим, нашият код ще изглежда така.

import subprocess

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

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

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

Ако искаме да съхраним стандартния изход на подпроцес в променлива, можем да го направим, като настроим аргумента capture_output на 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'

За достъп до изхода на даден процес използваме атрибута на екземпляр stdout.

В този случай искаме да съхраним изхода като низ, вместо байтове и можем да го направим, като зададем текстовия аргумент като 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.md

Идеално, след като вече знаем основите на библиотеката на подпроцесите, време е да преминем към някои примери за използване.

  8 най-добри SaaS HRMS за стартиращи фирми и предприятия

Примери за използване на подпроцес в Python

В този раздел ще прегледаме някои практически приложения на библиотеката на подпроцесите. Можете да проверите всички тях в това Github хранилище.

Програма за проверка

Една от основните употреби на тази библиотека е възможността за извършване на прости операции с операционната система.

Например прост скрипт, който проверява дали е инсталирана програма. В Linux можем да направим това с командата 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)

Забележка: В UNIX, когато дадена команда е успешна, нейният статус код е 0. В противен случай нещо се е объркало по време на изпълнението

Тъй като не използваме аргумента shell=True, можем да вземем сигурно въведеното от потребителя. Също така можем да проверим дали входът е валидна програма с модел на регулярен израз.

import subprocess

import re

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

secure_pattern = 'сб'

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

В този случай ние получаваме програмите от потребителя и използваме регулярен израз, който удостоверява, че програмният низ включва само букви и цифри. Проверяваме съществуването на всяка програма с for цикъл.

Прост Grep в Python

Вашият приятел Том има списък с шаблони в текстов файл и друг голям файл, в който иска да получи броя на съвпаденията за всеки шаблон. Той прекарваше часове в изпълнение на командата grep за всеки модел.

За щастие, вие знаете как да разрешите този проблем с Python и ще му помогнете да изпълни тази задача за няколко секунди.

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

Разглеждайки този файл, ние дефинираме две променливи, които са имената на файловете, с които искаме да работим. След това отваряме файла, който съдържа всички шаблони и ги итерираме. След това извикваме подпроцес, който изпълнява команда grep с флага „-c“ (означава брой) и определя изхода на съвпадението с условно условие.

Ако стартирате този файл (не забравяйте, че можете да изтеглите текстовите файлове от Github репо)

Настройте virtualenv с подпроцес

Едно от най-готините неща, които можете да правите с Python, е автоматизацията на процесите. Този вид скрипт може да ви спести часове време на седмица.

Например, ще създадем скрипт за настройка, който създава виртуална среда за нас и се опитва да намери файл requirements.txt в текущата директория, за да инсталира всички зависимости.

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

  Как да преместите бутона надолу в приложението Reddit

В този случай ние използваме множество процеси и анализираме данните, от които се нуждаем, в нашия скрипт на Python. Ние също използваме pathlib библиотека, която ни позволява да разберем дали файлът requirements.txt съществува.

Ако стартирате файла на Python, ще получите някои полезни съобщения за това какво се случва с операционната система.

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

Обърнете внимание, че получаваме изхода от инсталационния процес, защото не пренасочваме стандартния изход към променлива.

Стартирайте друг език за програмиране

Можем да изпълняваме други езици за програмиране с Python и да получаваме резултата от тези файлове. Това е възможно, защото подпроцесите взаимодействат директно с оперативната система.

Например, нека създадем програма hello world на C++ и Java. За да изпълните следния файл, ще трябва да инсталирате C++ и 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");  
    }  
}  

Знам, че това изглежда много код в сравнение с обикновен едноредов Python, но това е само за тестови цели.

Ще създадем Python скрипт, който изпълнява всички C++ и Java файлове в една директория. За да направим това, първо искаме да получим списък с файлове в зависимост от файловото разширение и глоб ни позволява да го направим лесно!

from glob import glob

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

cpp_files = glob('*.cpp')

След това можем да започнем да използваме подпроцеси за изпълнение на всеки тип файл.

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)

Един малък трик е да използваме лентата с функции на низ, за ​​да модифицираме изхода и да получим само това, от което се нуждаем.

Забележка: Бъдете внимателни, за да стартирате големи Java или C++ файлове, тъй като ние зареждаме техния изход в паметта и това може да доведе до изтичане на памет.

Отворете външни програми

Можем да стартираме други програми само като извикаме местоположението на техните двоични файлове чрез подпроцес.

Нека да го изпробваме, като отворим brave, моят предпочитан уеб браузър.

import subprocess

subprocess.run('brave')

Това ще отвори екземпляр на браузър или просто друг раздел, ако вече сте стартирали браузъра.

Както при всяка друга програма, която приема флагове, можем да ги използваме, за да произведем желаното поведение.

import subprocess

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

Да обобщим

Подпроцесът е компютърен процес, създаден от друг процес. Можем да проверим процесите, които компютърът ни изпълнява с инструменти като htop и диспечера на задачите.

Python има собствена библиотека за работа с подпроцеси. В момента функцията за изпълнение ни дава прост интерфейс за създаване и управление на подпроцеси.

Можем да създадем всякакви приложения с тях, защото взаимодействаме директно с операционната система.

И накрая, не забравяйте, че най-добрият начин да научите е да създадете нещо, което бихте искали да използвате.