Предыдущий пример работает, как предполагалось, но как быть, если во время сканирования файла нам потребуется файл изменить? В примере 4.3 показаны два подхода: в одном используются явные файлы, а в другом стандартные потоки ввода-вывода, которые можно перенаправить в командной строке.
Пример 4.3. PP4E\System\Filetools\filters.py
import sys
if not line: break
print(function(line), end=’’) # или: sys.stdout.write()
if __name__ == ‘__main__’: filter_stream(lambda line: line) # копировать stdin в stdout, если
# запущен как самостоятельный сценарий
Обратите внимание, что применение такой новейшей особенности, как менеджеры контекста, обсуждавшейся выше, позволило бы сэкономить несколько строк программного кода в реализации фильтра из примера 4.3, опирающегося на использование файлов, и гарантировало бы немедленное закрытие файлов в случае появления исключения в функции обработки:
def filter_files(name, function):
with open(name, ‘r’) as input, open(name + ‘.out’, ‘w’) as output: for line in input:
output.write(function(line)) # записать измененную строку
И снова, применение итераторов объектов файлов позволило бы упростить реализацию фильтра на основе потоков ввода-вывода:
def filter_stream(function):
for line in sys.stdin: # автоматически выполняет построчное чтение
print(function(line), end=’’)
Поскольку стандартные потоки ввода-вывода открываются автоматически, они обычно проще в использовании. Если запустить этот пример, как самостоятельный сценарий, он просто скопирует stdin в stdout:
C:\…\PP4E\System\Filetools> filters.py < hillbillies.txt
*Granny
+Jethro
*Elly May
+”Uncle Jed”
Однако этот модуль более полезен, когда он импортируется как библиотека (клиент предоставляет функцию обработки строк):
>>> from filters import filter_files
>>> filter_files(‘hillbillies.txt’, str.upper)
>>> print(open(‘hillbillies.txt.out’).read())
*GRANNY
+JETHRO
*ELLY MAY
+”UNCLE JED”
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011