Что такое подпроцесс в Python? [5 примеров использования]
Опубликовано: 2021-05-23Подпроцессы позволяют вам взаимодействовать с Оперативной системой на совершенно новом уровне.
Наш компьютер постоянно запускает подпроцессы. Фактически, просто читая эту статью, вы запускаете множество процессов, таких как диспетчер сети или сам интернет-браузер.
Самое замечательное в этом то, что любое действие, которое мы выполняем на нашем компьютере, включает вызов подпроцесса. Это остается верным, даже если мы пишем простой скрипт «hello world» на Python.
Концепция подпроцесса может показаться неясной, даже если вы уже какое-то время изучаете программирование. В этой статье мы подробно рассмотрим основную концепцию подпроцесса и то, как использовать стандартную библиотеку подпроцесса Python.
К концу этого урока вы:
- Понять концепцию подпроцесса
- Изучили основы библиотеки подпроцессов Python
- Практикуйте свои навыки Python с помощью полезных примеров
Давай займемся этим
Понятие подпроцесса
В широком смысле подпроцесс - это компьютерный процесс, созданный другим процессом.
Мы можем думать о подпроцессе как о дереве, в котором каждый родительский процесс имеет дочерние процессы, выполняемые за ним. Я знаю, что это может сбивать с толку, но давайте посмотрим на это с помощью простого рисунка.

Есть несколько способов визуализировать процесс, выполняющийся на нашем компьютере. Например, в 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 , команду, которую мы передаем в качестве аргумента.
Эта функция была введена в Python 3.5 как удобный ярлык для subprocess.Popen. Функция 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 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'Чтобы получить доступ к выходным данным процесса, мы используем атрибут экземпляра 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.
Программа проверки
Одно из основных применений этой библиотеки - возможность выполнять простые операции с ОС.
Например, простой скрипт, который проверяет, установлена ли программа. В 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 = '[\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')В этом случае мы получаем программы от пользователя и используем выражение регулярного выражения, которое удостоверяет, что строка программы включает только буквы и цифры. Мы проверяем наличие каждой программы с помощью цикла 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 ...")В этом случае мы используем несколько процессов и анализируем нужные нам данные в нашем скрипте 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 в каталоге. Для этого сначала мы хотим получить список файлов в зависимости от расширения файла, и glob позволяет нам это легко сделать!
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 есть собственная библиотека для работы с подпроцессами. В настоящее время функция run дает нам простой интерфейс для создания подпроцессов и управления ими.
Мы можем создавать с ними любые приложения, потому что мы напрямую взаимодействуем с ОС.
Наконец, помните, что лучший способ научиться - создавать что-то, что вы хотели бы использовать.
