Выбрать главу

b’Got this: “Lumberjack”\r\nThe meaning of life is 12 24\r\n’

Как будет показано в главе 5, при двунаправленном обмене данными с программами, подобными этим, необходимо проявлять осторожность - механизм буферизации потоков вывода может приводить к взаимоблокировке при чередовании операций записи и чтения и, в конечном счете, к необходимости использовать для решения проблемы такие инструменты, как Pexpect (подробнее об этой функции будет рассказываться далее в книге).

Наконец, модуль subprocess позволяет реализовать еще более экзотические формы управления потоками ввода-вывода - ниже демонстрируется соединение двух программ, где поток вывода одного сценария на языке Python подключается к потоку ввода другого. Сначала демонстрируется подключение с использованием командной оболочки, а затем - с помощью модуля subprocess:

C:\...\PP4E\System\Streams> python writer.py | python reader.py

Got this: “Help! Help! I’m being repressed!”

The meaning of life is 42 84

C:\...\PP4E\System\Streams> python

>>> from subprocess import Popen, PIPE

>>> p1 = Popen('python writer.py', stdout=PIPE)

>>> p2 = Popen('python reader.py', stdin=p1.stdout, stdout=PIPE)

>>> output = p2.communicate()[0]

>>> output

b’Got this: “Help! Help! I\’m being repressed!”\r\nThe meaning of life is 42 84\r\n’ >>> p2.returncode

0

Нечто похожее можно реализовать с помощью функции os.popen, но тот факт, что она может подключать только один из потоков ввода-вывода (но не оба), препятствует возможности перехватить вывод второго сценария:

>>> import os

>>> p1 = os.popen('python writer.py', 'r')

>>> p2 = os.popen('python reader.py', 'w')

>>> p2.write( p1.read() )

36

>>> X = p2.close()

Got this: “Help! Help! I’m being repressed!”

The meaning of life is 42 84 >>> print(X)

None

С точки зрения более широкой перспективы, функция os.popen и модуль subprocess являются переносимыми эквивалентами механизма перенаправления потоков ввода-вывода порождаемых программ, реализованного в командных оболочках для Unix-подобных систем. Однако реализации на языке Python с таким же успехом работают в Windows и предоставляют более универсальный способ запуска других программ из сценариев на языке Python. Строки команд, передаваемые им, могут иметь свои особенности в зависимости от платформы (например, в Unix список содержимого каталога можно получить с помощью команды ls, а в Windows - с помощью команды dir), но сами инструменты могут применяться на всех платформах, поддерживающих Python.

Запуск новых, независимых программ и подключение к их потокам ввода-вывода из родительской программы в Unix-подобных системах можно также реализовать с помощью функций os.fork, os.pipe, os.dup и некоторых функций из семейства os.exec. Кроме того, они обеспечивают еще один способ перенаправления потоков ввода-вывода и являются низкоуровневыми эквивалентами таким инструментам, как os.popen (функция os.fork доступна в Windows, в версии Python для Cygwin).

Однако все перечисленные функции являются более сложными инструментами параллельной обработки данных, поэтому мы отложим дальнейшее их обсуждение до главы 5, где дополнительно будет рассказываться об организации каналов и получении кодов завершения. А к модулю subprocess мы вернемся в главе 6, где на его основе реализуем механизм регрессионного тестирования, перехватывающий все три стандартных потока ввода-вывода тестируемого сценария - потоки ввода, вывода и ошибок.

Но перед этим, в главе 4, мы продолжим наше исследование системных интерфейсов, реализованных в библиотеке языка Python, и познако-

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

Python и csh

Если вы знакомы с другими распространенными языками сценариев командной оболочки, вам может оказаться полезным сравнить их с языком Python. Ниже приводится простой сценарий на языке командной оболочки csh для Unix, который отправляет по электронной почте все файлы с расширением .py из текущего рабочего каталога (то есть все файлы с исходным программным кодом на языке Python) на фиктивный, как мы надеемся, электронный адрес:

#!/bin/csh foreach x (*.py) echo $x

mail eric@halfabee.com -s $x < $x end

Ниже приводится эквивалентный сценарий на языке Python:

#!/usr/bin/python import os, glob for x in glob.glob(‘*.py’): print(x)

os.system(‘mail eric@halfabee.com -s %s < %s’ % (x, x))

Он выглядит более подробным. Язык Python, в отличие от csh, не предназначен для разработки исключительно сценариев командной строки, поэтому системные интерфейсы необходимо импортировать и вызывать явно. А так как Python не является языком программирования, ориентированным на работу исключительно со строками, строки символов необходимо заключать в кавычки, как в языке C.