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-строку.
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
import random
import solution
def test():
annotations = solution.generate_pin.__annotations__
assert 'return' in annotations, "You should add a return type annotation"
for seed in [1, 7, 42]:
random.seed(seed)
result = solution.generate_pin()
random.seed(seed)
d1 = random.randint(0, 9)
d2 = random.randint(0, 9)
d3 = random.randint(0, 9)
d4 = random.randint(0, 9)
assert result == f"{d1}{d2}{d3}{d4}"
assert len(result) == 4Решение учителя откроется через:
20:00
