Все приведенные выше способы перенаправления стандартных потоков действуют для программ, написанных на любом языке программирования, который обеспечивает возможность перехватывать стандартные потоки, и зависят скорее от процессора командной строки оболочки, чем от самого интерпретатора. Операции перенаправления в командной строке, такие как < filename и | program, обрабатываются оболочкой, а не интерпретатором Python. Более «питонистый» способ перенаправления можно реализовать в самих сценариях, присваивая переменным sys.stdin и sys.stdout объекты, похожие на файлы.
Это возможно благодаря тому, что любой объект, который набором методов напоминает файл, может выступать в роли стандартного потока. Важен не конкретный тип объекта, а его интерфейс (иногда его называют протоколом). Это означает следующее:
• Любой объект, обладающий методами чтения, может быть присвоен переменной sys.stdin, в результате чего ввод будет осуществляться через методы чтения этого объекта.
• Любой объект, обладающий методами записи, может быть присвоен переменной sys.stdout; в результате весь стандартный вывод будет отправляться методам этого объекта.
Так как функции print и input просто вызывают методы write и readline объектов, на которые ссылаются sys.stdout и sys.stdin, мы можем генерировать и перехватывать стандартные текстовые потоки с помощью объектов, реализованных с помощью классов.
Если вам уже приходилось изучать язык Python, вы, вероятно, знаете, что подобная совместимость по интерфейсам обычно называется полиморфизмом — неважно, чем является объект, и неважно, что делают его методы, — важно, чтобы этот объект предоставлял ожидаемый интерфейс. Такое либеральное отношение к типам данных объясняет значительную долю гибкости и выразительности программного кода на языке Python. Ниже демонстрируется способ, позволяющий сценариям переопределять собственные потоки ввода-вывода. В примере 3.9 приводится вспомогательный модуль, демонстрирующий эту идею.
Пример 3.9. PP4E\System\Streams\redirect.py
объекты, похожие на файлы, один из которых сохраняет в строке текст, отправленный в стандартный поток вывода, а другой обеспечивает ввод текста из строки в стандартный поток ввода; функция redirect вызывает переданную ей функцию, для которой стандартные потоки вывода и ввода будут связаны с объектами, похожими на файлы;
# импортировать встроенный модуль
class Output:
def __init__(self): self.text = ‘’
def write(self, string):
self.text += string
def writelines(self, lines):