Python: Пакеты

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

Чтобы организовывать модули в более крупные логические группы, в Python используют пакеты. Пакет представляет собой директорию с Python-файлами.

Например, структура проекта может выглядеть так:

project/
├── main.py
├── payments/
│   ├── stripe.py
│   └── paypal.py
└── users/
    ├── auth.py
    └── profile.py

В этом примере payments и users являются пакетами, а stripe.py, paypal.py, auth.py и profile.py — модулями.

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

Импорт из пакета

К модулям внутри пакета обращаются через точку:

import payments.stripe

После импорта можно использовать содержимое модуля:

import payments.stripe

payments.stripe.create_payment()

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

Импорт конкретного модуля

Часто импортируют не весь путь, а конкретный модуль:

from payments import stripe

stripe.create_payment()

Такой способ сокращает запись и делает код компактнее.

Вложенные пакеты

Пакеты могут содержать другие пакеты:

project/
└── app/
    └── payments/
        ├── stripe/
        │   ├── client.py
        │   └── api.py
        └── paypal.py

В этом случае путь к модулю становится длиннее:

from app.payments.stripe import client

Такая структура часто встречается в больших проектах. Она помогает разделять код на независимые части.

Пакеты и пространства имен

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

Например:

project/
├── admin/
│   └── config.py
└── user/
    └── config.py

Здесь существуют два разных модуля config.py.

Python различает их по полному пути:

import admin.config
import user.config

Без пакетов такие имена конфликтовали бы между собой.

Файл init.py

Раньше для создания пакета внутри директории обязательно размещали файл __init__.py:

payments/
├── __init__.py
├── stripe.py
└── paypal.py

Этот файл сообщал Python, что директорию нужно воспринимать как пакет.

В современных версиях Python пакеты могут работать и без __init__.py. Тем не менее этот файл до сих пор часто используется. Обычно в нем размещают общий код и настройки пакета.

Задание

Реализуйте функцию generate_pin(). Она возвращает случайный четырёхзначный PIN-код в виде строки.

Каждый разряд PIN-кода — независимое случайное целое число от 0 до 9.

print(generate_pin())  # => например, "4823" или "0571"
print(generate_pin())  # => например, "1942" или "0037"

Укажите аннотацию типа возвращаемого значения.

Подсказка

Сгенерируйте каждую из четырёх цифр через random.randint(0, 9) и соберите строку через f-строку.

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются