Чтобы конкретизировать вышеизложенное, в примере 12.12 показано, как некоторые из описанных сложностей влияют на перенаправление стандартных потоков ввода-вывода. В нем выполняется попытка связать потоки ввода-вывода с файлами в текстовом и двоичном режимах, создаваемых функцией open, и обратиться к ним с помощью встроенных функций print и input, как это обычно делается в сценариях.
Пример 12.12. PP4E\Internet\Sockets\test-stream-modes.py
проверка эффекта связывания стандартных потоков ввода-вывода с файлами, открытыми в текстовом и двоичном режимах; то же справедливо и для socket. makefile: функция print требует текстовый режим, а текстовый режим, в свою очередь, препятствует отключению буферизации —
используйте ключ —u или вызывайте метод sys.stdout.flush()
import sys
def reader(F):
tmp, sys.stdin = sys.stdin, F line = input() print(line) sys.stdin = tmp
reader(open(‘test-stream-modes.py’)) # работает: input() возвращает
# текст
reader(open(‘test-stream-modes.py’, ‘rb’)) # работает: но input() # возвращает байты
def writer(F):
tmp, sys.stdout = sys.stdout, F print(99, ‘spam’) sys.stdout = tmp
writer( open(‘temp’, ‘w’) ) # работает: print() передает .write()
# текст str
print( open(‘temp’).read() )
writer( open(‘temp’, ‘wb’) ) # ОШИБКА в print: двоичный режим
# требует байты
writer( open(‘temp‘, ‘w‘, 0) ) # ОШИБКА в open: буферизация в текстовом
# режиме обязательна
Если запустить этот сценарий, последние две инструкции в нем потерпят неудачу — вторая с конца терпит неудачу потому, что print пытается вывести текстовую строку в двоичный файл (что вообще недопустимо для файлов). А последняя инструкция терпит неудачу потому, что в Python 3.X не допускается открывать текстовые файлы в небуферизован- ном режиме (текстовый режим предполагает кодирование символов Юникода). Ниже приводятся сообщения об ошибках, которые выводятся при попытке запустить этот сценарий: первое сообщение выводится, если запустить сценарий в приведенном виде, а второе появляется, если закомментировать вторую с конца инструкцию (я немного отредактировал текст исключения для большей наглядности):
C:\…\PP4E\Internet\Sockets> test—stream—modes.py
b’"""\r’
99 spam
Traceback (most recent call last):
File "C:\…\PP4E\Internet\Sockets\test-stream-modes.py", line 26, in <module>
writer( open(‘temp’, ‘wb’) ) # ОШИБКА в print: двоичный режим.
File "C:\…\PP4E\Internet\Sockets\test-stream-modes.py", line 20, in writer
print(99, ‘spam’)
TypeError: must be bytes or buffer, not str
(TypeError: данные должны быть типа bytes или buffer, а не str)
C:\…\PP4E\Internet\Sockets> test-streams-binary.py
b’"""\r’
99 spam
Traceback (most recent call last):
File "C:\…\PP4E\Internet\Sockets\test-stream-modes.py", line 27, in <module>
writer( open(‘temp’, ‘w’, 0) ) # ОШИБКА в open: буферизация
# в текстовом…
ValueError: can’t have unbuffered text I/O
(ValueError: не поддерживается небуферизованный ввод-вывод текста)
То же самое относится к объектам файлов-оберток для сокетов, создаваемых с помощью метода makefile сокетов — они должны открываться в текстовом режиме, чтобы обеспечить поддержку print, и также должны открываться в текстовом режиме, если желательно, чтобы функция input принимала текстовые строки, но текстовый режим препятствует использованию небуферизованного режима для файлов:
> >> from socket import *
> >> s = socket() # по умолчанию для tcp/ip (AF_INET, SOCK_STREAM)
> >> s.makefile(‘w‘, 0) # эта инструкция работала в Python 2.X
Traceback (most recent call last):
File "C:\Python31\lib\socket.py", line 151, in makefile
ValueError: unbuffered streams must be binary
(ValueError: небуферизованные потоки ввода-вывода должны быть двоичными)
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011