Модули, пакеты и импорты
Как разложить код по файлам: import, __init__.py, __name__.
Бытовая аналогия: мастерская с ящиками инструментов
Пока проект маленький, все инструменты валяются на одном столе — это один большой файл. Когда инструментов становится много, их раскладывают по ящикам (модулям), а ящики — по шкафам (пакетам). Нужен молоток — открываешь нужный ящик, а не перерываешь весь стол.
Модуль — это просто .py-файл. Пакет — это папка с модулями. import — это «достать нужный инструмент из ящика».
Модуль — это файл
Любой файл my_tools.py уже является модулем. ФункцииИменованный блок кода, который можно вызывать многократно. Может принимать аргументы и возвращать результат. и переменныеИменованное хранилище для значения. Имя связывается со значением через присваивание: x = 5. из него можно использовать в другом файле через import. Вы уже делали это с готовыми модулями: import math, import random.
Три способа импорта
Пакет — это папка с модулями
Когда модулей много, их группируют в пакет — папку с файлом __init__.py (может быть пустым; он помечает папку как пакет). Внутрь импортируют через точку: from пакет.модуль import функция.
myproject/
├── main.py
└── shop/ # пакет (папка)
├── __init__.py # помечает папку как пакет (может быть пустым)
├── cart.py # модуль shop.cart
└── prices.py # модуль shop.prices
# --- shop/prices.py ---
TAX = 0.2
def with_tax(price):
return price * (1 + TAX)
# --- shop/cart.py ---
from shop.prices import with_tax # абсолютный импорт
def total(items):
return sum(with_tax(p) for p in items)
# --- main.py ---
from shop.cart import total
print(total([100, 200])) # 360.0Абсолютные и относительные импорты
- Абсолютный импорт указывает полный путь от корня проекта:
from shop.prices import with_tax. Понятный и надёжный — рекомендуется по умолчанию. - Относительный импорт указывает путь относительно текущего модуля через точки:
from .prices import with_tax(точка = «текущий пакет»). Работает только внутри пакета.
Защита if __name__ == "__main__"
Когда файл запускают напрямую (python main.py), Python кладёт в переменную __name__ строкуТекстовое значение в кавычках: "привет". Неизменяема. По-английски string (str). "__main__". А когда файл импортируют — туда попадает имя модуля. Проверка if __name__ == "__main__": позволяет отделить «код для запуска» от «кода для импорта»: при импорте демонстрационный блок не выполнится.
Правило хорошего тона: в модуле оставляют определения (функции, классыШаблон для создания объектов: описывает их данные (атрибуты) и поведение (методы).), а любой запускаемый код прячут под if __name__ == "__main__":. Тогда модуль можно и импортировать, и запускать — без побочных эффектов при импорте.
🔮 Предскажите вывод
Файл запускают напрямую командой python app.py. Что он выведет?
Разбор. Файл запущен напрямую, значит __name__ == "__main__" — истина. Выполнится ветка if: сначала main, затем area(3, 4) → 12. Ветка else (imported) сработала бы только при импорте файла как модуля.
⚠️ Частые ошибки новичков
- Называют свой файл как стандартный модуль (например,
random.pyилиmath.py) — тогдаimport randomподхватит ваш файл вместо библиотеки и всё сломается. - Пишут скобки после import:
import(math)— это ошибка. Правильно без скобок:import math. - Забывают, что при импорте выполняется весь модуль. Код вне функций и вне
if __name__ == "__main__"сработает уже в момент импорта.
Ключевое слово import пишется без скобок. Скобки нужны при вызове функций, а import — это инструкция, а не функция.
run_mode(), которая возвращает строку "direct", если модуль запущен напрямую (__name__ == "__main__"), и "imported" в противном случае. Подсказка: сравните значение __name__ внутри функции.sqrt и константу pi из модуля math (через from math import ...) и напишите функцию circle_len(r), возвращающую длину окружности 2 * pi * r, а также используйте sqrt в функции diagonal(a, b), возвращающей sqrt(a*a + b*b).✅ Что вы узнали
- Модуль — это
.py-файл; пакет — папка с модулями и файлом__init__.py. - Три способа импорта:
import module,from module import name,import module as alias. - Абсолютный импорт (
from shop.prices import ...) надёжнее; относительный (from .prices import ...) — внутри пакета. if __name__ == "__main__":отделяет запускаемый код от импортируемого — при импорте он не выполняется.
Комментарии
Загрузка…
Загрузка комментариев…