Що таке підпроцес у Python? [5 Usage Examples]

| | 0 Comments| 3:51 AM
Categories:

Підпроцеси дозволяють вам взаємодіяти з операційною системою на абсолютно новому рівні.

Наш комп’ютер постійно запускає підпроцеси. Насправді, просто читаючи цю статтю, ви запускаєте багато процесів, наприклад мережевий менеджер або сам інтернет-браузер.

Цікаво те, що будь-яка дія, яку ми виконуємо на своєму комп’ютері, передбачає виклик підпроцесу. Це залишається вірним, навіть якщо ми пишемо простий сценарій «hello world» на python.

Поняття підпроцесу може здатися незрозумілим, навіть якщо ви деякий час вивчаєте програмування. Ця стаття детально розгляне основну концепцію підпроцесу та те, як використовувати Python стандартна бібліотека підпроцесу.

До кінця цього підручника ви:

  • Зрозумійте концепцію підпроцесу
  • Вивчили основи бібліотеки підпроцесів Python
  • Практикував свої навички Python на корисних прикладах

Давайте вникнемо в це

Поняття підпроцесу

Загалом кажучи, підпроцес — це a комп’ютерний процес створений іншим процесом.

Ми можемо розглядати підпроцес як дерево, у якому за кожним батьківським процесом працюють дочірні процеси. Я знаю, що це може бути досить заплутаним, але давайте подивимося на це за допомогою простої графіки.

Є кілька способів візуалізації процесу, що виконується на нашому комп’ютері. Наприклад, в UNIX (Linux & MAC) ми маємо htop, який є інтерактивним переглядачем процесів.

Режим дерева є найкориснішим інструментом для перегляду запущених підпроцесів. Ми можемо активувати його за допомогою F5.

Якщо ми уважно подивимось на розділ команд, то побачимо структуру процесів, що виконуються на нашому комп’ютері.

Все починається з /sbin/init це команда, яка запускає кожен процес на нашому комп’ютері. З цього моменту ми бачимо початок інших процесів, таких як xfce4-screenshoter і xfce4-terminal (що веде до ще більшої кількості підпроцесів)

Дивлячись на Windows, ми маємо міфічне диспетчер завдань що стане в нагоді під час зупинки тих програм, що виходять з ладу на нашій машині.

Тепер ми маємо кришталево чітку концепцію. Давайте подивимося, як ми можемо реалізувати підпроцеси в Python.

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

Підпроцес у Python — це завдання, яке сценарій python делегує операційній системі (ОС).

Бібліотека підпроцесів дозволяє нам виконувати підпроцеси та керувати ними безпосередньо з 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.

Це означає, що ми можемо робити все, що завгодно, доки наша ОС дозволяє (і доки ви не видалите свою кореневу файлову систему 😅).

Давайте подивимося, як ним користуватися, створивши простий сценарій, який перераховує файли поточного каталогу.

Перше застосування підпроцесу

Спочатку створимо файл list_dir.py. Це буде файл, у якому ми будемо експериментувати зі списком файлів.

touch list_dir.py

Тепер давайте відкриємо цей файл і використаємо наступний код.

import subprocess 

subprocess.run('ls')

Спочатку ми імпортуємо модуль підпроцесу, а потім використовуємо функцію run, яка запускає команду, яку ми передаємо як аргумент.

  8 послуг зі створення компаній, які допоможуть вам відкрити бізнес у Великобританії

Ця функція була представлена ​​в 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

Ідеально, тепер, коли ми знаємо основи бібліотеки підпроцесів, настав час перейти до деяких прикладів використання.

Приклади використання підпроцесу в Python

У цьому розділі ми збираємося розглянути деякі практичні використання бібліотеки підпроцесів. Ви можете перевірити їх усі тут Репозиторій Github.

Програма перевірки

Одним із основних застосувань цієї бібліотеки є можливість виконувати прості операції з ОС.

  Roblox Mighty Secunda Codes: викупити зараз

Наприклад, простий скрипт, який перевіряє, чи встановлена ​​програма. У 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)

Налаштуйте віртуальне середовище з підпроцесом

Одна з найкрутіших речей, які ви можете зробити з 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 ...")

  Як заборонити вашому Google Home записувати всі ваші розмови

У цьому випадку ми використовуємо кілька процесів і розбираємо потрібні нам дані в нашому сценарії 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 має власну бібліотеку для роботи з підпроцесами. Наразі функція запуску дає нам простий інтерфейс для створення та керування підпроцесами.

З ними ми можемо створювати будь-які програми, тому що ми взаємодіємо безпосередньо з ОС.

Зрештою, пам’ятайте, що найкращий спосіб навчитися – створити те, що ви б хотіли використовувати.