Сокрытие данных в модулях
_X и __all__
Как особый случай, существует возможность начинать имена переменных с одного символа подчеркивания (например, _X), чтобы предотвратить их переаписывание, когда клиент выполняет импортирование модуля инструкцией from*. Этот прием на самом деле предназначен только для минимизации загрязнения пространства имен – так как инструкция from* копирует все имена, импортирующий модуль может получить больше, чем предполагал (включая имена, которые перезапишут имена импортирующего модуля). Символы подчеркивания не являются объявлением «частных» данных: вы по-прежнему можете видеть эти имена и изменять их с помощью других форм импортирования, таких как инструкция import.Альтернативный способ достижения эффекта сокрытия данных, напоминающий соглашение об именовании _X, заключается в присвоении на верхнем уровне модуля переменной __all__ списка строк с именами переменных.
Например:
__all__ = [“Error”, “encode”, “decode”] # Экспортируются только эти имена
При использовании этого приема инструкция from* будет копировать только имена, перечисленные в списке __all__.
В действительности это соглашение, обратное соглашению _X:
переменная __all__ идентифицирует имена, доступные для копирования,
тогда как соглашение _X идентифицирует имена, недоступные для копирования.
Интерпретатор Python сначала отыскивает список __all__ в модуле, и если он отсутствует, инструкция from* копирует все имена, которые не начинаются с единственного символа подчеркивания.
Включение будущих возможностей языка
В языке периодически появляются изменения, которые могут повлиять на работоспособность существующего программного кода. Сначала они появляются в виде расширений, которые по умолчанию отключены. Чтобы включить такие расширения, используется инструкция импорта специального вида:
from __future__ import имя_функциональной_особенности
Эта инструкция вообще должна появляться в самом начале файла модуля (воз-можно, сразу же вслед за строкой документирования), потому что она включает специальный режим компиляции программного кода для каждого отдельно взятого модуля.
Смешанные режимы использования: __name__ и __main__
Ниже демонстрируется специальный прием, позволяющий импортировать файлы как модули и запускать их как самостоятельные программы. Каждый модуль обладает встроенным атрибутом __name__, который устанавливается интерпретатором следующим образом:
•Если файл запускается как главный файл программы, атрибуту __name__ на запуске присваивается значение “__main__”.
•Если файл импортируется, атрибуту __name__ присваивается имя модуля, под которым он будет известен клиенту.
Благодаря этому модуль может проверить собственный атрибут __name__и определить, был ли он запущен как самостоятельная программа или импортирован другим модулем.
Например, предположим, что мы создаем файл модуля с именем runme.py, который экспортирует единственную функцию с именем tester:
def tester(): print(“It’s Christmas in Heaven...”) if __name__ == ‘__main__’: #Только когда запускается,tester() # а не импортируется
Этот модуль определяет функцию для клиентов и может импортироваться как обычный модуль:
% python>>> import runme>>> runme.tester() It’sChristmasinHeaven...
Но в самом конце модуля имеется программный код, который вызывает функцию, когда этот файл запускается как самостоятельная программа:
% python runme.py It’s Christmas in Heaven...
На практике программный код самопроверки в конце файла, заключенный в условную инструкцию, проверяющую атрибут __name__, является, пожалуй, самым распространенным и удобным способом модульного тестирования в языке Python.
Изменение пути поиска модулей
Путь поиска модулей – это список каталогов, и что этот список можно дополнить с помощью переменной окружения PYTHONPATH и файлов .pth.
Но сами программы на языке Python могут изменять путь поиска, изменяя встроенный список с именем sys.path (атрибут path встроенного модуля sys). Список sys.path инициализируется во время запуска программы, однако и после этого допускается удалять, добавлять и изменять компоненты списка по своему усмотрению:
>>> import sys>>> sys.path[‘’, ‘C:\\users’, ‘C:\\Windows\\system32\\python30.zip’, ...далее опущено...] >>> sys.path.append(‘C:\\sourcedir’)# Дополнение пути поиска модулей >>> importstring# Новый каталог будет участвовать# в поиске
Модули – это объекты: метапрограммы
Способы получения доступа к атрибуту модуля:
M.name# Полное имя объекта M.__dict__[‘name’] # Доступ с использованием словаря пространства имен sys.modules[‘M’].name # Доступ через таблицу загруженных модулей getattr(M, ‘name’) # Доступ с помощью встроенной функции
Обеспечивая доступ к внутреннему устройству модулей, интерпретатор помогает создавать программы, управляющие другими программами.
Импортирование модулей по имени в виде строки
Имя модуля в инструкции import или from является именем переменной. Тем не менее иногда ваша программа будет получать имя модуля, который следует импортировать, в виде строки во время выполнения (например, в случае, когда пользователь выбирает имя модуля внутри графического интерфейса). К сожалению, невозможно напрямую использовать инструкции импорта для загрузки модуля, имя которого задано в виде строки, – в этих инструкциях интерпретатор ожидает получить имя переменной, а не строку. Например:
>>> import “string” File “”, line 1 import “string” ^SyntaxError: invalid syntax
Точно так же невозможно импортировать модуль, если просто присвоить стро-ку переменной:
x = “string” import x
Здесь интерпретатор попытается импортировать файл x.py, а не модуль string – имя в инструкции import превращается в имя переменной, которой присваивается объект загружаемого модуля, и идентифицирует внешний файл буквально.
Чтобы решить эту проблему, необходим специальный инструмент, выполняющий динамически загрузку модулей, имена которых создаются в виде строк во время выполнения. Обычно для этого конструируется строка программного кода, содержащая инструкцию import, которая затем передается встроенной функции exec для исполнения (в Python 2.6 exec – это инструкция, но она может использоваться точно так же, как показано здесь, – круглые скобки просто игнорируются интерпретатором):
>>> modname = “string” >>> exec(“import “ + modname) # Выполняется как строка программного кода >>> string# Модуль был импортирован в пространство имен
Функция exec скомпилирует строку в код и передаст его интерпретатору для исполнения.
Единственный настоящий недостаток функции exec состоит в том, что она должна компилировать инструкцию import всякий раз, когда она запускается,
Если импортировать приходится достаточно часто, программный код может работать немного быстрее при использовании встроенной функции
__ import__
которая выполняет загрузку модуля, получая его имя в виде строки. Результат получается тот же самый, но функция __import__ возвращает объект модуля, поэтому его надо присвоить переменной, чтобы сохранить:
>>> modname = “string” >>> string = __import__(modname) >>> string