Структура проекта: модули и пакеты в 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.py

Python package init py (инициализация пакета с __init__.py)

Содержимое math_ops.py:

def multiply(a, b):
    return a * b

Python создание модулей (создание модулей в python)

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

from my_package import math_ops
print(math_ops.multiply(3, 4))  # 12

Python 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

Создание модулей в Python - comments

En
Python создание модулей (python)