Структура проекта: модули и пакеты в Python
Основные способы создания модулей в Python
Как создать простой модуль и импортировать его в другой скрипт?
Базовое решение заключается в сохранении исполняемого кода в файле с расширением .py. Любой такой файл автоматически становится модулем, доступным для импорта. Рассмотрим пример: создадим файл calc.py с функциями сложения и вычитания.
# calc.py
def add(a, b):
"""Возвращает сумму двух чисел"""
return a + b
def subtract(a, b):
"""Возвращает разность двух чисел"""
return a - bимпорт кода python (импорт кода python)
Теперь в другом файле main.py импортируем модуль и используем его функции.
# main.py
import calc
result_add = calc.add(10, 5)
result_sub = calc.subtract(10, 5)
print(result_add, result_sub) # Вывод: 15 5ошибка импорта python (ошибка импорта модуля в python)
Типичная ошибка: модуль не найден, если файл лежит не в той же директории или интерпретатор запущен из другого каталога. Решение: добавить путь к модулю в sys.path или использовать относительные/абсолютные импорты внутри пакета.
Как организовать несколько модулей в пакет?
Для создания пакета достаточно поместить файлы модулей в отдельную директорию и добавить в неё файл __init__.py (может быть пустым). Пример структуры:
my_package/
__init__.py
math_ops.py
string_ops.pyPython package init py (инициализация пакета с __init__.py)
Содержимое math_ops.py:
def multiply(a, b):
return a * bPython создание модулей (создание модулей в python)
Импорт из пакета:
from my_package import math_ops
print(math_ops.multiply(3, 4)) # 12Python init file (файл __init__.py в python)
Проблема: при большом количестве файлов __init__.py может стать слишком громоздким. Решение: использовать автоматический импорт через __all__ в __init__.py.
Как избежать конфликтов имен при импорте?
Алиасы (переименование) с помощью ключевого слова as помогают избежать коллизий с другими идентификаторами.
import calc as c # теперь обращение через c.add()
import random as rd
print(c.add(2, 3)) # 5Как импортировать только нужные элементы модуля?
Конструкция from module import name позволяет получить прямой доступ к определённым объектам, избегая обращения через имя модуля.
from calc import add
print(add(10, 20)) # 30
# Функция subtract не импортирована - её вызов вызовет NameErrorОшибка: случайная замена имени импортированной функции локальной переменной приведёт к потере доступа. Рекомендуется не использовать одинаковые имена для разных целей.
Как импортировать модуль по имени, заданному строкой?
Динамический импорт выполняется через importlib.
import importlib
module_name = "calc"
calc_module = importlib.import_module(module_name)
print(calc_module.add(5, 6)) # 11Проблема: динамический импорт сложнее отслеживать, он работает медленнее статического. Используется, когда имя модуля заранее неизвестно (например, плагины).
Расширенные примеры создания и использования модулей
Пример 1. Модуль с классами, константами и докстрингом.
# geometry.py
"""Модуль для работы с геометрическими фигурами"""
import math
PI = 3.1415926535
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return PI * self.radius ** 2
def perimeter_of_square(side):
return 4 * side# Импорт и использование import geometry circle = geometry.Circle(5) print(circle.area()) # 78.5398163375 print(geometry.perimeter_of_square(3)) # 12 print(geometry.PI) # 3.1415926535
Пример 2. Пакет с явным экспортом через __all__.
# shapes/__init__.py
__all__ = ["circle", "square"]
from . import circle
from . import square
# shapes/circle.py
def area(radius):
return 3.14 * radius * radius
# shapes/square.py
def area(side):
return side * side# Теперь импорт звёздочкой даёт только circle и square from shapes import * print(circle.area(3)) # 28.26 print(square.area(4)) # 16
Пример 3. Относительные импорты внутри пакета.
# package/sub/__init__.py
from ..tools import helper
# package/tools.py
def helper():
return "this is helper"
# package/sub/module.py
from . import helper
print(helper.helper()) # "this is helper"# Запуск из корня проекта (не изнутри пакета) # python -m package.sub.module # Вывод: this is helper
Пример 4. Динамический импорт с проверкой доступности.
import importlib
import sys
module_name = "xml.etree.ElementTree" # имя в виде строки
try:
et = importlib.import_module(module_name)
print("Модуль загружен:", et)
root = et.Element("root")
print("Создан элемент:", root.tag)
except ImportError:
print("Модуль не найден", file=sys.stderr)# Вывод: # Модуль загружен:# Создан элемент: root