Мы уже знаем, что в Python код хранится в отдельных файлах, называемых модулями. Но если начать делить код достаточно большого проекта на модули, то довольно быстро может возникнуть желание сгруппировать несколько модулей "по смыслу". Или же мы захотим вынести часть модулей из проекта с целью использования оных в других проектах. Для объединения модулей в группы и служат пакеты (packages).

Итак, пакет - это папка с файлами модулей, имеющая имя в формате "snakecase" и содержащая помимо прочего специальный модуль с именем "__init__.py". Именно наличие этого специального файла подсказывает интерпретатору Python, что папку следует воспринимать именно как пакет.

Простейший пакет

Давайте рассмотрим пример простейшего пакета. Пусть пакет состоит из папки package и __init__.py внутри этой папки:

package/
└── __init__.py

Файл __init__.py пусть содержит код:

# file __init__.py
NAME = 'super_package'

Это пусть и небольшой, но уже полноценный пакет. Такой пакет можно импортировать так же, как мы импортировали бы модуль:

import package

print(package.name)

Заметьте — мы не импортировали файл __init__.py непосредственно. При первом обращении к пакету Python автоматически импортирует модуль __init__.py в этом пакете. Поэтому, очевидно, нельзя импортировать "просто папку" — папка без файла __init__.py не будет полноценным пакетом!

Содержимое пакета

С простым пакетом всё ясно — его можно использовать как модуль. Но давайте уже перейдём к группировке в пакете нескольких модулей! Для этого в пакет положим ещё два модуля:

package/
├── constants.py
├── functions.py
└── __init__.py

Содержимое новых модулей примем таким:

# file constants.py
PERSON = 'Alice'

# file functions.py
def greet(who):
    print('Hello, ' + who + '!')

Когда пакет содержит другие модули, кроме __init__.py, таковые можно импортировать по их именам. В главе про модули упоминались два варианта импортирования — квалифицированный импорт и импортирование отдельных определений. Квалифицированный импорт в данном случае будет выглядеть так:

import package.functions
import package.constants

package.functions.greet(package.constants.PERSON)  # => Hello, Alice!

Этот вариант самый понятный: в строчке вызова функции greet сразу видно, откуда пришла функция, а откуда — её аргумент. Но писать имя пакета и имя модуля каждый раз — утомительно! Давайте импортируем сами функцию и аргумент:

from package.functions import greet
from package.constants import PERSON

greet(PERSON)  # => Hello, Alice!

Так строчка вызова функции выглядит гораздо лучше! Но помните, что тому, кто будет читать этот код в дальнейшем, потребуется посмотреть в блок импортов, чтобы узнать, откуда функция и константа появились.

Для продолжения нужно перейти в курс и вступить в него.