Операция перенаправления стандартного потока ошибок из командной строки выглядит несколько сложнее и хуже переносится. В большинстве Unix-подобных систем перехватить вывод в поток stderr обычно можно с помощью операции перенаправления вида command > output 2>&1. Однако в некоторых версиях Windows она не действует, и даже в некоторых оболочках для Unix она может иметь другой вид - за дополнительной информацией обращайтесь к страницам справочного руководства по вашей оболочке.
Возможность перенаправления с помощью функции print
Вследствие того, что переназначение атрибутов потоков приобрело большую популярность, встроенная функция print в языке Python также была дополнена возможностью явно указывать файл для вывода. Следующая инструкция:
print(stuff, file=afile) # afile - это объект, а не имя строковой переменной
выведет stuff в afile, а не в поток sys.stdout. По своему действию это напоминает присваивание объекта переменной sys.stdout, но в данном случае отпадает необходимость сохранять и восстанавливать первоначальное значение, чтобы вернуться к использованию оригинального потока вывода (как было показано в разделе, описывающем перенаправление потоков в объекты). Например:
import sys
print(‘spam’ * 2, file=sys.stderr)
выведет текст в объект стандартного потока ошибок, а не в sys.stdout, причем такое перенаправление будет действовать только для данного вызова функции print. Следующий вызов функции print (без аргумента file) выведет текст в стандартный поток вывода, как обычно. Точно так же в качестве выходного файла можно передать свой собственный объект или экземпляр класса из стандартной библиотеки:
>>> from io import StringIO >>> buff = StringIO()
>>> print(42, file=buff)
>>> print('spam', file=buff)
>>> print(buff.getvalue())
42
spam
>>> from redirect import Output >>> buff = Output()
>>> print(43, file=buff)
>>> print('eggs', file=buff)
>>> print(buff.text)
43
eggs
Другие варианты перенаправления: еще раз об os.popen и subprocess
Ближе к концу предыдущей главы мы впервые встретились с функцией os.popen и родственной ей subprocess.Popen, которые предоставляют возможность перенаправления потоков ввода-вывода других команд из программы на языке Python. Как мы видели, эти инструменты могут использоваться для выполнения команд оболочки (например, команд, которые обычно вводятся с клавиатуры в ответ на приглашение DOS или csh), и они возвращают объект Python, похожий на файл, соединенный с потоком вывода команды, - чтение из объекта файла позволяет сценарию принимать вывод другой программы. Однако эти инструменты могут также использоваться для соединения с потоками ввода.
Благодаря этому функцию os.popen и инструменты из модуля subprocess можно рассматривать как еще один способ перенаправления потоков порождаемых программ, родственный только что рассмотренным приемам. Их действие во многом похоже на действие оператора | объединения команд в конвейер (фактически имена этих инструментов означают «pipe open» - «открыть канал»), но они выполняются внутри сценария и предоставляют схожий с файлами интерфейс к потокам данных, связанных каналом. По духу они близки функции redirect, но запускают не функции, а программы, и потоки ввода-вывода обрабатываются в порождающем сценарии как файлы (не привязанные к объектам классов). Эти инструменты перенаправляют потоки ввода-вывода программ, запускаемых сценарием, а не самого сценария.
Перенаправление ввода или вывода с помощью os.popen
Передавая в функцию флаг нужного режима, мы фактически выполняем перенаправление в файл потока ввода или вывода программы, порожденной сценарием, и можем получить код завершения этой программы вызовом метода close (значение None говорит об успешном завершении). Чтобы проиллюстрировать это, рассмотрим следующие два сценария:
C:\...\PP4E\System\Streams> type hello-out.py print(‘Hello shell world’)
C:\...\PP4E\System\Streams> type hello-in.py inp = input()
open(‘hello-in.txt’, ‘w’).write(‘Hello ‘ + inp + ‘\n’)
Эти сценарии могут запускаться из командной строки, как обычно:
C:\...\PP4E\System\Streams> python hello-out.py Hello shell world
C:\...\PP4E\System\Streams> python hello-in.py Brian
C:\...\PP4E\System\Streams> type hello-in.txt Hello Brian
В предыдущей главе мы видели, что сценарии на языке Python могут также читать вывод других программ и подобных им сценариев, как показано ниже:
C:\...\PP4E\System\Streams> python >>> import os
>>> pipe = os.popen('python hello-out.py') # ‘r’ - по умолчанию, чтение stdout