В следующей главе мы будем использовать инструменты из модулей sys и os для решения обычных системных задач, но объем данной книги не позволяет приводить полные списки содержимого встречающихся модулей. Если вы этого еще не сделали, ознакомьтесь с содержимым таких модулей, как os и sys, обратившись к ресурсам, описанным выше. А теперь перейдем к исследованию дополнительных системных инструментов в контексте более широких понятий системного программирования.
subprocess, os.popen и итераторы
В главе 4 мы будем исследовать итераторы файлов, но перед тем, как взять эту книгу, вы наверняка уже ознакомились с основами. Поскольку объекты, возвращаемые функцией os.popen, обладают итераторами, позволяющими читать данные по одной строке за раз, использование метода readlines этих объектов обычно является излишним. Например, ниже приводится пример чтения строк, которые выводятся другой программой, без явного использования методов чтения:
>>> import os
>>> for line in os.popen('dir /B *.py'): print(line, end='')
helloshell.py more.py __init__.py
Интересно, что в Python 3.1 функция os.popen реализована с использованием объекта subprocess.Popen, с которым мы познакомились в этой главе. Вы можете убедиться в этом, заглянув в файл os.py в стандартной библиотеке Python (в Windows вы найдете этот файл в каталоге C:\Python31\Lib). Результатом вызова функции os.popen является объект, управляющий объектом Popen и его каналами:
>>> I = os.popen('dir /B *.py')
>>> I
<os._wrap_close object at 0x013BC750>
Этот объект-обертка канала определяет метод__iter__, поэтому он
поддерживает возможность итераций по строкам, которые могут выполняться автоматически (например, в цикле for, как показано выше) или вручную. Любопытно отметить, что, несмотря на наличие в объекте-обертке поддержки прямого вызова метода__next__,
как если бы этот объект обладал собственным итератором (подобно простым файлам), тем не менее он не поддерживает встроенную функцию next, хотя последняя, вероятно, просто вызывает метод __next__:
>>> I = os.popen('dir /B *.py')
>>> I.__next__()
'helloshell.py\n'
>>> I = os.popen('dir /B *.py')
>>> next(I)
TypeError: _wrap_close object is not an iterator
Причина такого поведения скрыта глубоко в недрах реализации -
прямой вызов метода__next__перехватывается методом__ge-
tattr__, определенном в объекте-обертке канала, и преобразуется
в вызов метода обернутого объекта. Но функция next обращается к механизму перегрузки операторов, который в Python 3.X действует в обход метода__getattr__, когда производится вызов методов со специальными именами, такими как__next__. Поскольку
объект-обертка канала не определяет собственный метод__next__,
обращение к нему не перехватывается и не передается обернутому объекту, что приводит к ошибке при вызове встроенной функции next. Как детально объясняется в книге «Изучаем Python», метод
__getattr__обертки не вызывается по той простой причине, что
в Python 3.X поиск методов начинается не с экземпляра, а с класса.
Такое поведение может быть или не быть ожидаемым, но вам не придется беспокоиться об этом при выполнении итераций по строкам в канале с помощью цикла for, генераторов и других инструментов. Тем не менее, чтобы обеспечить выполнение итераций вручную, необходимо сначала вызвать встроенную функцию iter -
она вызовет метод__iter__объекта-обертки канала и обеспечит
корректную поддержку обоих способов перемещения по строкам:
>>> I = os.popen('dir /B *.py')
>>> I = iter(I) # так поступает цикл for
>>> I. next () # теперь обе формы итераций действуют правильно
'helloshell.py\n'
>>> next(I)
‘more.py\n’
3
Контекст выполнения сценариев
«Ваши аргументы, пожалуйста!»
Сценарии на языке Python выполняются не в вакууме (хотя, возможно, вы слышали что-то иное). В зависимости от платформы и процедуры запуска программы на языке Python выполняются в определенном контексте, то есть обладают информацией, которая автоматически передается операционной системой при запуске программы. Например, у сценариев есть доступ к следующим видам входных данных системного уровня и интерфейсов:
Текущий рабочий каталог
Функция os.getcwd предоставляет доступ к каталогу, из которого запущен сценарий и значение которого неявно используют многие инструменты для работы с файлами.
Аргументы командной строки
sys.argv предоставляет доступ к словам в команде, с помощью которой была запущена программа и которые играют роль входных данных сценария.
Переменные оболочки
os.environ предоставляет интерфейс к переменным окружения, созданным в охватывающей оболочке (или родительской программой) и передаваемым сценарию.