Если потребуется принимать входные данные из stdin и использовать консоль для взаимодействия с пользователем, в сценарий нужно будет внести дополнительные изменения: нам придется отказаться от использования функции input и задействовать специальные интерфейсы для чтения ответов пользователя непосредственно с клавиатуры. В Windows такую возможность обеспечивает модуль msvcrt, входящий в состав стандартной библиотеки Python; в большинстве Unix-подобных систем достаточно будет использовать файл устройства /dev/tty.
Поскольку это достаточно редкая ситуация, мы рассмотрим полную реализацию предложенного решения. В примере 3.8 показана модифицированная версия сценария more.py для Windows, которая постранично выводит данные из стандартного потока ввода при вызове без аргументов, а кроме того, в ней используются низкоуровневые и зависящие от платформы средства взаимодействия с пользователем через клавиатуру.
Пример 3.8. PP4E\System\Streams\moreplus.py
обеспечивает постраничный вывод в stdout содержимого строки, файла или потока; если запускается как самостоятельный сценарий, обеспечивает постраничный вывод содержимого потока stdin или файла, имя которого указывается в виде аргумента командной строки; когда входные данные поступают через поток stdin, исключается возможность использовать его для получения ответов пользователя --вместо этого можно использовать платформозависимые инструменты или графический интерфейс;
import sys def getreply():
читает клавишу, нажатую пользователем,
даже если stdin перенаправлен в файл или канал
if sys.stdin.isatty(): # если stdin связан с консолью,
return input(‘?’) # читать ответ из stdin
else:
if sys.platform[:3] == ‘win’: # если stdin был перенаправлен,
import msvcrt # его нельзя использовать для чтения
msvcrt.putch(b’?’) # ответа пользователя
key = msvcrt.getche() # использовать инструмент консоли
msvcrt.putch(b’\n’) # getch(), которая не выводит символ
return key # для нажатой клавиши
else:
assert False, ‘platform not supported’
#для Linux: open(‘/dev/tty’).readline()[:-1]
def more(text, numlines=10):
реализует постраничный вывод содержимого строки в stdout
lines = text.splitlines() while lines:
chunk = lines[:numlines]
lines = lines[numlines:]
for line in chunk: print(line)
if lines and getreply() not in [b’y’, b’Y’]: break
if name == ‘ main ’: # если выполняется, а не импортируется
if len(sys.argv) == 1: # если нет аргументов командной строки
more(sys.stdin.read()) # вывести содержимое stdin
else:
more(open(sys.argv[1]).read()) # иначе вывести содержимое файла
Большая часть нововведений этой версии находится в функции getreply Метод файла isatty сообщает, соединен ли stdin с консолью, - если да функция просто считывает ответ из stdin, как и раньше. Конечно, по добная дополнительная логика необходима только в сценариях, предусматривающих возможность взаимодействия с пользователем и получения входных данных из stdin. В приложениях с графическим интерфейсом можно было бы, например, выводить диалог, реализовать обработку событий от клавиатуры в виде функций обратного вызова и так далее (знакомиться с графическими интерфейсами мы будем в главе 7).
Имея на вооружении функцию getreply, можно спокойно запускать утилиту moreplus различными способами. Как и прежде, можно импортировать и непосредственно вызывать функцию этого модуля, передавая ей ту строку, которую требуется вывести постранично:
>>> from moreplus import more
>>> more(open('adderSmall.py').readO)
import sys
print(sum(int(line) for line in sys.stdin))
И так же, как и прежде, при запуске с аргументом командной строки этот сценарий интерактивно будет пролистывать текст указанного файла:
C:\...\PP4E\System\Streams> python moreplus.py adderSmall.py
import sys
print(sum(int(line) for line in sys.stdin))
C:\...\PP4E\System\Streams> python moreplus.py moreplus.py
обеспечивает постраничный вывод в stdout содержимого строки, файла или потока; если запускается как самостоятельный сценарий, обеспечивает постраничный вывод содержимого потока stdin или файла, имя которого указывается в виде аргумента командной строки; когда входные данные поступают через поток stdin, исключается возможность использовать его для получения ответов пользователя - вместо этого можно использовать платформозависимые инструменты или графический интерфейс;