Возможности модулей в Python

Сокрытие данных в модулях

_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