Стандартные потоки ввода-вывода
sys.stdin, stdout и stderr экспортируют три потока ввода-вывода, лежащие в центре инструментов командной оболочки, и могут использоваться в сценариях с помощью функции print, os.popen и модулем
subprocess, представленными в главе 2, с помощью класса io. StringIO и других инструментов.
Такие инструменты могут играть роль входных данных сценариев, параметров настройки и так далее. В этой главе мы исследуем все эти четыре инструмента работы с контекстом - их интерфейсы в Python и типичные области их использования.
Текущий рабочий каталог
Понятие текущего рабочего каталога (current working directory, CWD) оказывается ключевым при выполнении некоторых сценариев: это всегда неявно определенное место в файловой системе, где предполагается размещение обрабатываемых сценарием файлов, если в их именах отсутствует абсолютный путь к каталогу. Как мы уже видели, функция os.getcwd позволяет сценарию получить имя текущего рабочего каталога в явном виде, а функция os.chdir позволяет сценарию переместиться в новый текущий рабочий каталог.
Однако имейте в виду, что для имен файлов, не содержащих полного пути, подразумевается, что они находятся в текущем рабочем каталоге, и это не имеет никакого отношения к переменной окружения PYTHONPATH. С технической точки зрения сценарий всегда запускается из текущего рабочего каталога, а не из каталога, содержащего файл сценария. Напротив, при импортировании модулей поиск всегда начинается в каталоге, содержащем сценарий, а не в текущем рабочем каталоге (если только сценарий не размещен в текущем рабочем каталоге). Поскольку это тонкое различие, на котором часто попадаются новички, изучим его более подробно.
Текущий рабочий каталог, файлы и путь поиска модулей
Если запустить сценарий Python, введя в команду, например, python dir1\dir2\file. py, - текущим рабочим каталогом будет каталог, в котором вы находились при вводе этой команды, но не dirl\dir2. С другой стороны, Python автоматически добавляет путь к каталогу, где находится сценарий, в начало пути поиска модулей, поэтому file.py всегда сможет импортировать другие файлы из dirl\dir2, откуда бы он ни был запущен. Чтобы проиллюстрировать это, напишем простой сценарий, выводящий имя текущего рабочего каталога и путь поиска модулей:
C:\...\PP4E\System> type whereami.py
import os, sys
print(‘my os.getcwd =>’, os.getcwd()) # вывод текущего рабочего каталога print(‘my sys.path =>’, sys.path[:6]) # вывод первых 6 каталогов в пути поиска input() # ожидает нажатия клавиши
Теперь при запуске этого сценария в том каталоге, где он находится, будет выбран ожидаемый текущий рабочий каталог, и имя этого каталога будет добавлено в начало пути поиска. Мы уже встречались со списком sys.path, содержащим путь поиска модулей, - первый его элемент может быть пустой строкой, обозначающей текущий рабочий каталог при работе в интерактивной оболочке; здесь большая часть пути к текущему рабочему каталогу усекается до «...» при отображении:
C:\...\PP4E\System> set PYTHONPATH=C:\PP4thEd\Examples
C:\...\PP4E\System> python whereami.py
my os.getcwd => C:\...\PP4E\System
my sys.path => [‘C:\\...\\PP4E\\System’, ‘C:\\PP4thEd\\Examples’, ...другие
элементы... ]
Если запускать этот сценарий из других каталогов, вслед за нашим перемещением переместится и текущий рабочий каталог (это каталог, в котором вводятся команды), а Python будет добавлять в начало пути поиска модулей каталог, где находится сам сценарий, что позволит сценарию по-прежнему видеть файлы в своем исходном каталоге. Например, если запустить сценарий, поднявшись на один уровень (..), каталог System будет добавлен в начало списка sys.path и станет первым каталогом, в котором Python станет искать модули, импортируемые сценарием whereami.py: первый элемент списка будет нацеливать импорт обратно на каталог, содержащий выполняемый сценарий. Однако поиск файлов, имена которых не содержат полного пути, будет выполняться относительно текущего рабочего каталога (C:\PP4thEd\Examples\ PP4E), а не в его подкаталоге System:
C:\...\PP4E\System> cd ..
C:\...\PP4E> python System\whereami.py
my os.getcwd => C:\...\PP4E
my sys.path => [‘C:\\...\\PP4E\\System’, ‘C:\\PP4thEd\\Examples’, ...другие
элементы... ]
C:\...\PP4E> cd System\temp
C:\...\PP4E\System\temp> python ..\whereami.py
my os.getcwd => C:\...\PP4E\System\temp
my sys.path => [‘C:\\...\\PP4E\\System’, ‘C:\\PP4thEd\\Examples’, ...]
В результате поиск файлов, имена которых в сценарии не содержат полных путей, будет выполняться в том месте, где была введена команда (os.getcwd), но операции импортирования по-прежнему будут иметь доступ к каталогу, где находится выполняемый сценарий (через первый элемент в списке sys.path). Наконец, если файл запускается щелчком на ярлыке, текущим рабочим каталогом станет каталог, содержащий файл, на котором выполнен щелчок. Например, следующие строки будут выведены в новом окне консоли DOS при двойном щелчке на whereami.py в проводнике Windows: