Python Пакеты

Python Пакеты — средство группировки модулей.

Python Пакеты могут быть разбросаны по каталогам разной глубины вложенности, поэтому нужно умудриться сделать так, чтобы все нужные пакеты были найдены и нужные модули из них были импортированы.

Пакеты

Пакеты позволяют сгруппировать коллекцию модулей под общим именем пакета.

Этот приём позволяет решить проблему конфликтов имён между именами модулей, используемых в различных приложениях. Пакет создаётся как каталог с тем же именем, в котором создаётся файл с именем __init__.py

Затем в этом каталоге можно сохранить исходные файлы, скомпилированные расширения и подпакеты. Например, пакет может иметь такую структуру:

Graphics/
‘    __init__.py
‘    Primitive/
‘        __init__.py
‘        lines.py
‘        fill.py
‘        text.py
‘        …
‘    Graph2d/
‘        __init__.py
‘        plot2d.py
‘        …
‘    Graph3d/
‘        __init__.py
‘        plot3d.py
‘        …
Formats/
‘        __init__.py
‘        gif.py
‘        png.py
‘        tiff.py
‘        jpeg.py

Загрузка модулей из пакета может быть выполнена с помощью инструкции import несколькими способами:
>>> import Graphics.Primitive.fill
Загрузит модуль Graphics.Primitive.fill. Объекты, содержащиеся в этом модуле, получат имена, такие как Graphics.Primitive.fill. floodfill(img,x,y,color).

>>> from Graphics.Primitive import fill
Загрузит модуль fill, но сделает возможным обращаться к нему без использования префикса с именем пакета;
например, fill. floodfill(img,x,y,color).

>>> from Graphics.Primitive.fill import floodfill
Загрузит модуль fill, но сделает возможным обращаться к функции floodfill непосредственно; например, floodfill(img,x,y,color).

Всякий раз, когда какая-либо часть пакета импортируется впервые, выполняется программный код в файле __init__.py. Этот файл может быть пустым, но может также содержать программный код, выполняющий инициализацию пакета. Выполнены будут все файлы __init__.py, которые встретятся инструкции import в процессе её выполнения.

То есть инструкция import Graphics.Primitive.fill, показанная выше, сначала выполнит файл __init__.py в каталоге Graphics, а затем файл __init__.py в каталоге Primitive. Существует одна проблема, характерная для пакетов, связанная с выполнением такой инструкции:
from Graphics.Primitive import *

Когда программист использует подобную инструкцию, он обычно хочет импортировать все модули, ассоциированные с пакетом, в текущее пространство имен.

Однако из-за того, что соглашения по именованию файлов могут изменяться от системы к системе (особенно это относится к регистру символов), Python не в состоянии точно определить, какие модули должны загружаться.

Как результат, эта инструкция просто импортирует все имена, которые определены в файле __init__.py, находящемся в каталоге Primitive.

Это поведение можно изменить, определив список __all__, содержащий имена всех модулей в пакете. Этот список должен быть объявлен в файле __init__.py пакета, например:
# Graphics/Primitive/__init__.py
__all__ = [“lines”,”text”,”fill”]

Теперь, когда интерпретатор встретит инструкцию from Graphics.Primitive import *, он загрузит все перечисленные модули, как и следовало ожидать.

Ещё одна малозаметная проблема, связанная с пакетами, касается модулей, которые должны импортировать другие модули из того же пакета.

Например, допустим, что модуль Graphics.Primitive.fill должен импортировать модуль Graphics.Primitive.lines.

Для этого можно просто указать полностью квалифицированное имя модуля (например, from Graphics.Primitives import lines) или выполнить импортирование относительно текущего пакета, например:
# fill.py
from . import lines

В этом примере символ . в инструкции from . import lines ссылается на тот же каталог, где находится вызывающий модуль. То есть данная инструкция будет искать модуль lines в том же каталоге, где находится файл fill. py.

При импортировании модулей из пакета следует быть особенно внимательными и не использовать инструкцию вида import module. В старых версиях Python было не очевидно, ссылается ли инструкция import module на модуль в стандартной библиотеке или на модуль в пакете.

В старых версиях Python такая инструкция сначала пыталась загрузить модуль из того же каталога пакета, где находится импортирующий модуль, и только потом, в случае неудачи, делалась попытка загрузить модуль из стандартной библиотеки.

Однако в Python 3, инструкция import предполагает, что указан абсолютный путь, и будет пытаться загрузить модуль из стандартной библиотеки. Использование инструкции импортирования по относительному пути более чётко говорит о Ваших намерениях.

Возможность импортирования по относительному пути можно также использовать для загрузки модулей, находящихся в других каталогах того же пакета.

Например, если в модуле Graphics.Graph2D.plot2d потребуется импортировать модуль Graphics.Primitives.lines, инструкция импорта будет иметь следующий вид:
# plot2d.py
from ..Primitives import lines

В этом примере символы .. перемещают точку начала поиска на уровень выше в дереве каталогов, а имя Primitives перемещает её вниз, в другой каталог пакета.

Импорт по относительному пути может выполняться только при использовании инструкции импортирования вида from module import symbol. То есть такие инструкции, как import ..Primitives.lines или import .lines, будут рассматриваться как синтаксическая ошибка.

Кроме того, имя symbol должно быть допустимым идентификатором. Поэтому такая инструкция, как from .. import Primitives.lines, также считается ошибочной. Наконец, импортирование по относительному пути может выполняться только для модулей в пакете; не допускается использовать эту возможность для ссылки на модули, которые просто находятся в другом каталоге файловой системы.

Импортирование по одному только имени пакета не приводит к импортированию всех модулей, содержащихся в этом пакете. Например, следующий фрагмент не будет работать:
import Graphics
Graphics.Primitive.fill.floodfill(img,x,y,color) # Ошибка!

Однако, так как инструкция import Graphics выполнит файл __init__.py в каталоге Graphics, в него можно добавить инструкции импортирования по относительному пути, которые автоматически загрузят все модули, как показано ниже:
# Graphics/__init__.py
from . import Primitive, Graph2d, Graph3d

# Graphics/Primitive/__init__.py
from . import lines, fill, text, …

Теперь инструкция import Graphics будет импортировать все модули и обеспечит их доступность по полностью квалифицированным именам.

Ещё раз подчеркну, что инструкция импортирования пакета по относительному пути должна использоваться именно так, как показано выше.

Если использовать простую инструкцию, такую как import module, она попытается загрузить модуль из стандартной библиотеки.

Наконец, когда интерпретатор импортирует пакет, он объявляет специальную переменную __path__, содержащую список каталогов, в которых выполняется поиск модулей пакета (__path__ представляет собой аналог списка sys.path для пакета).

Переменная __path__ доступна для программного кода в файлах __init__.py и изначально содержит единственный элемент с именем каталога пакета.

При необходимости пакет может добавлять в список __path__ дополнительные каталоги, чтобы изменить путь поиска модулей. Это может потребоваться в случае сложной организации дерева каталогов пакета в файловой системе, которая не совпадает с иерархией пакета.

Думаю, что постепенно научусь использовать Python Пакеты и модули из них.

Приглашаю всех высказываться в Комментариях. Критику и обмен опытом одобряю и приветствую. В хороших комментариях сохраняю ссылку на сайт автора!

И не забывайте, пожалуйста, нажимать на кнопки социальных сетей, которые расположены под текстом каждой страницы сайта.
Python ПакетыПродолжение тут…

Deviz_3

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Проверка комментариев включена. Прежде чем Ваши комментарии будут опубликованы пройдет какое-то время.