Модули в Python
Представьте, что вы пишете большую программу, которая постепенно превращается в сотни или даже тысячи строк кода. Держать всё в одном файле становится неудобно — код трудно поддерживать и находить нужные части. Здесь на помощь приходят модули! 📦
Что такое модуль?
Модуль в Python — это просто файл с расширением .py, содержащий код Python (функции, классы, переменные), который можно импортировать и использовать в других программах.
Модули помогают:
- Организовать связанный код в отдельные файлы
- Повторно использовать код в разных программах
- Избежать конфликтов имен
- Сделать код более читаемым и поддерживаемым
Создание собственного модуля и его импорт
Создать модуль в Python очень просто — достаточно написать код в файле с расширением .py. Заведём mymath.py и тут же положим рядом несколько main-скриптов, которые показывают разные способы его подключить:
1# Импорт всего модуля2import mymath3 4# Все имена доступны через префикс mymath.5 6result = mymath.add(5, 3)7print(f"5 + 3 = {result}") # 5 + 3 = 88 9area = mymath.PI * 5 ** 210print(f"Площадь круга радиусом 5: {area}")11 12# Площадь круга радиусом 5: 78.5397513 14 В дереве слева — наш модуль mymath.py и четыре варианта main_*.py, каждый показывает свой способ импорта. Переключайтесь между вкладками. Ниже короткий разбор, когда какой удобнее.
Импорт всего модуля
Самый прямой способ — import mymath (см. main_basic.py). Все имена остаются «внутри» модуля и доступны через префикс: mymath.add, mymath.PI. Удобно, когда из одного модуля нужно много функций и важно видеть, откуда они пришли.
Импорт конкретных элементов
from mymath import add, multiply (см. main_specific.py). Импортируем только нужное и обращаемся без префикса. Хорошо для пары часто вызываемых функций; плохо, когда через сотню строк забываешь, откуда взялась add.
Импорт с переименованием
import mymath as mm (см. main_aliased.py). Нужно, если имя модуля длинное (numpy as np, pandas as pd — те самые случаи) или конфликтует с локальной переменной.
Импорт всех элементов
from mymath import * (см. main_star.py). Импортирует всё подряд в текущее пространство имён. В обычном коде так делать обычно не стоит: теряется источник имён, легко получить конфликт. Нормально только в REPL и иногда в тестах.
Структура модуля
Хороший модуль обычно содержит блоки в таком порядке:
- Документация — строка в тройных кавычках в самом начале файла, описывает назначение модуля.
- Импорты — сначала стандартная библиотека, затем сторонние пакеты, затем собственные модули.
- Константы — глобальные значения, которые не меняются в работе.
- Классы — определения классов.
- Функции — определения функций.
- Код для выполнения — блок if __name__ == "__main__": для запуска модуля как самостоятельной программы (про него ниже).
Если посмотреть на наш mymath.py, то документация уже есть в первой строке, константа PI на месте, дальше идут функции. Импортов нет (модуль самодостаточный), классов нет (для арифметики они не нужны). Блок «код для выполнения» добавим через секцию, в разговоре про __name__.
Пакеты
Когда модуль mymath.py разрастается (например, появляются разные группы операций), его можно разделить на несколько файлов и собрать в пакет. Пакет в Python — это директория с файлом __init__.py. Когда вы пишете import mathlib, Python видит этот __init__.py и понимает, что директория — это импортируемый пакет.
Превратим наш модуль в пакет: разнесём функции по тематикам, а в __init__.py соберём публичный интерфейс.
1"""mathlib: пакет с математическими функциями."""2 3**version** = "0.1"4 5# Re-export, чтобы пользователи могли писать from mathlib import add6 7from mathlib.basic import PI, add, subtract8from mathlib.advanced import multiply, divide9 Что изменилось:
- Файлов теперь четыре, но снаружи это всё ещё «один математический модуль» — пользователь пишет from mathlib import add, как и раньше с mymath.
- mathlib/__init__.py контролирует, что считается публичным API: имена, перечисленные через from .basic import ... и from .advanced import ..., доступны прямо как mathlib.add.
- Внутри пакета модули могут ссылаться друг на друга через относительные импорты: from . import basic (тот же каталог), from .. import other (родительский каталог).
Если пакет растёт ещё, его можно разбить на подпакеты — например, mathlib/stats/ со своим __init__.py и модулями статистических функций. Принцип тот же, просто на уровень глубже.
Специальные переменные модуля
В Python модули имеют несколько специальных переменных:
Переменная __name__: модуль как программа vs как зависимость
Внутри Python у каждого модуля есть переменная __name__. Когда модуль импортируют, в ней лежит его имя ("mymath"). А когда модуль запускают напрямую (python mymath.py), Python кладёт в неё специальное значение "__main__". Это позволяет внутри модуля написать блок «делай это только при прямом запуске»:
1"""Модуль с математическими функциями."""2 3PI = 3.141594 5def add(a, b):6return a + b7 8def divide(a, b):9if b == 0:10raise ValueError("Деление на ноль невозможно")11return a / b12 13# Этот блок выполняется только при прямом запуске:14 15# python mymath.py16 17# При импорте (import mymath) в другом файле он не сработает.18 19if **name** == "**main**":20print(f"PI = {PI}")21print(f"add(2, 3) = {add(2, 3)}")22 Запустите python mymath.py — увидите вывод if-блока. Запустите python main.py — этот блок промолчит, и в выводе будет только 8 от вызова в main.py.
Переменная __all__: что попадает в from module import *
По умолчанию from mymath import * импортирует все имена, которые не начинаются с подчёркивания. Если хочется явно зафиксировать публичный API модуля, добавляют переменную __all__ со списком имён.
1"""Модуль с математическими функциями."""2 3# Только эти имена попадут в from mymath import *4 5**all** = ["PI", "add"]6 7PI = 3.141598_INTERNAL = "не должен попасть наружу"9 10def add(a, b):11return a + b12 13def subtract(a, b):14return a - b15 16def _round_helper(value):17"""Внутренний помощник, не для публичного использования."""18return round(value, 2)19 Через from mymath import * пришли только PI и add — именно те, что перечислены в __all__. Остальные имена (subtract, _INTERNAL, _round_helper) остались в модуле и доступны только при явном импорте: from mymath import subtract.
Лучшие практики при работе с модулями
-
Один модуль — одна ответственность: Каждый модуль должен отвечать за одну конкретную функциональность.
-
Понятные имена модулей: Используйте описательные, но краткие имена (например, data_processing.py, user_interface.py).
-
Документация: Каждый модуль должен начинаться с документации, описывающей его назначение.
-
Импорты в начале файла: Все импорты должны быть в начале модуля.
-
Явные импорты: Предпочитайте from module import specific_thing вместо from module import *.
-
Приватные имена: Начинайте имена "приватных" функций и переменных с подчеркивания (_private_function).
-
Тестирование модуля: Используйте блок if __name__ == "__main__": для тестирования модуля.
Проверка понимания
Давайте проверим, насколько хорошо вы усвоили тему модулей:
Что будет выведено при запуске main.py из проекта ниже?
1import test_module2 3print(test_module.hello())4 Помните, модули и пакеты помогают применять принцип "Не повторяйся" (DRY - Don't Repeat Yourself) и делают ваши программы более профессиональными. Организуйте свой код мудро, и вам будет намного легче развивать его в будущем! 💪
