Найти в Дзене
Skill Up In IT

Python | Модули и пакеты

Когда ваши программы на Python
становятся больше и сложнее, возникает необходимость организовывать код
логически. Модули и пакеты — это механизмы Python для структурирования
кода, которые позволяют разбивать программу на несколько файлов,
повторно использовать код и создавать четкие пространства имен. Модуль — это просто файл с расширением .py, содержащий код на Python. Модуль может определять функции, классы и переменные, а также может включать исполняемый код. Давайте создадим наш первый модуль. Создайте файл math_operations.py: # math_operations.py
def add(a, b):
"""Возвращает сумму двух чисел"""
return a + b
def subtract(a, b):
"""Возвращает разность двух чисел"""
return a - b
def multiply(a, b):
"""Возвращает произведение двух чисел"""
return a * b
def divide(a, b):
"""Возвращает частное двух чисел"""
if b == 0:
raise ValueError("Нельзя делить на ноль!")
return a / b
# Константа
PI = 3.14159
# Исполняемый код (будет выполнен
Оглавление

Когда ваши программы на Python
становятся больше и сложнее, возникает необходимость организовывать код
логически. Модули и пакеты — это механизмы Python для структурирования
кода, которые позволяют разбивать программу на несколько файлов,
повторно использовать код и создавать четкие пространства имен.

Что такое модули?

Определение модуля

Модуль — это просто файл с расширением .py, содержащий код на Python. Модуль может определять функции, классы и переменные, а также может включать исполняемый код.

Создание простого модуля

Давайте создадим наш первый модуль. Создайте файл math_operations.py:

# math_operations.py

def add(a, b):
"""Возвращает сумму двух чисел"""
return a + b

def subtract(a, b):
"""Возвращает разность двух чисел"""
return a - b

def multiply(a, b):
"""Возвращает произведение двух чисел"""
return a * b

def divide(a, b):
"""Возвращает частное двух чисел"""
if b == 0:
raise ValueError("Нельзя делить на ноль!")
return a / b

# Константа
PI = 3.14159

# Исполняемый код (будет выполнен при импорте)
print("Модуль math_operations загружен")

Импорт модуля

Теперь создадим другой файл main.py в той же папке и импортируем наш модуль:

# main.py

# Импорт всего модуля
import math_operations

# Использование функций из модуля
result = math_operations.add(5, 3)
print(f"5 + 3 = {result}")

result = math_operations.multiply(4, 7)
print(f"4 * 7 = {result}")

# Доступ к константе
print(f"Значение PI: {math_operations.PI}")

Различные способы импорта

Python предлагает несколько способов импорта:

# 1. Импорт всего модуля
import math_operations

# 2. Импорт с псевдонимом
import math_operations as mo

# 3. Импорт конкретных функций
from math_operations import add, multiply

# 4. Импорт всех функций (не рекомендуется)
from math_operations import *

# 5. Импорт с псевдонимом для функции
from math_operations import divide as div

Практический пример

# calculator.py
from math_operations import add, subtract, multiply, divide

def calculate(operation, a, b):
"""Выполняет математическую операцию"""
operations = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide
}

if operation in operations:
return operations[operation](a, b)
else:
raise ValueError(f"Неизвестная операция: {operation}")

# Использование
try:
result = calculate('+', 10, 5)
print(f"10 + 5 = {result}")

result = calculate('/', 10, 2)
print(f"10 / 2 = {result}")
except ValueError as e:
print(f"Ошибка: {e}")

Встроенные модули Python

Python поставляется с богатой стандартной библиотекой модулей. Вот некоторые популярные:

Модуль math

import math

# Математические функции
print(f"Квадратный корень из 16: {math.sqrt(16)}")
print(f"Синус 90 градусов: {math.sin(math.radians(90))}")
print(f"Число π: {math.pi}")
print(f"Округление вверх: {math.ceil(3.2)}")
print(f"Округление вниз: {math.floor(3.8)}")

Модуль datetime

import datetime

# Работа с датой и временем
now = datetime.datetime.now()
print(f"Текущее время: {now}")

today = datetime.date.today()
print(f"Сегодня: {today}")

# Создание конкретной даты
birthday = datetime.date(1990, 5, 15)
print(f"День рождения: {birthday}")

# Разница между датами
age = today - birthday
print(f"Дней с рождения: {age.days}")

Модуль os

import os

# Информация о операционной системе
print(f"Текущая рабочая директория: {os.getcwd()}")
print(f"Имя пользователя: {os.getenv('USERNAME')}")

# Работа с файловой системой
files = os.listdir('.')
print("Файлы в текущей директории:")
for file in files:
print(f" {file}")

# Создание директории
if not os.path.exists('my_folder'):
os.makedirs('my_folder')
print("Директория создана")

Модуль random

import random

# Генерация случайных чисел
print(f"Случайное число от 1 до 10: {random.randint(1, 10)}")
print(f"Случайное дробное число: {random.random()}")

# Выбор случайного элемента
fruits = ['яблоко', 'банан', 'апельсин', 'виноград']
print(f"Случайный фрукт: {random.choice(fruits)}")

# Перемешивание списка
random.shuffle(fruits)
print(f"Перемешанные фрукты: {fruits}")

Создание пакетов

Что такое пакеты?

Пакет — это способ организации связанных модулей в иерархии директорий. Пакет — это просто директория, содержащая специальный файл __init__.py.

Структура простого пакета

my_package/
│ __init__.py
│ module1.py
│ module2.py
└── subpackage/
│ __init__.py
│ submodule1.py
│ submodule2.py

Создание пакета шаг за шагом

  1. Создайте структуру директорий:

shapes/
│ __init__.py
│ circle.py
│ rectangle.py
│ triangle.py
└── utils/
│ __init__.py
│ calculator.py
│ validator.py
  1. Создайте файл shapes/__init__.py:

# shapes/__init__.py

# Импортируем основные функции для удобного доступа
from .circle import calculate_area as circle_area
from .rectangle import calculate_area as rectangle_area
from .triangle import calculate_area as triangle_area

__version__ = "1.0.0"
__all__ = ['circle_area', 'rectangle_area', 'triangle_area']
  1. Создайте модуль shapes/circle.py:

# shapes/circle.py
from ..utils.calculator import validate_positive

def calculate_area(radius):
"""Вычисляет площадь круга"""
validate_positive(radius, "radius")
return 3.14159 * radius ** 2

def calculate_circumference(radius):
"""Вычисляет длину окружности"""
validate_positive(radius, "radius")
return 2 * 3.14159 * radius
  1. Создайте модуль shapes/rectangle.py:

# shapes/rectangle.py
from ..utils.calculator import validate_positive

def calculate_area(length, width):
"""Вычисляет площадь прямоугольника"""
validate_positive(length, "length")
validate_positive(width, "width")
return length * width

def calculate_perimeter(length, width):
"""Вычисляет периметр прямоугольника"""
validate_positive(length, "length")
validate_positive(width, "width")
return 2 * (length + width)
  1. Создайте модуль shapes/triangle.py:
# shapes/triangle.py
from ..utils.calculator import validate_positive

def calculate_area(base, height):
"""Вычисляет площадь треугольника"""
validate_positive(base, "base")
validate_positive(height, "height")
return 0.5 * base * height
  1. Создайте подпакет utils:

Файл shapes/utils/__init__.py:

# shapes/utils/__init__.py
from .calculator import validate_positive
from .validator import validate_triangle_sides

__all__ = ['validate_positive', 'validate_triangle_sides']

Файл shapes/utils/calculator.py:

# shapes/utils/calculator.py

def validate_positive(value, name):
"""Проверяет, что значение положительное"""
if value <= 0:
raise ValueError(f"{name} должен быть положительным числом")

Файл shapes/utils/validator.py:

# shapes/utils/validator.py

def validate_triangle_sides(a, b, c):
"""Проверяет, могут ли стороны образовать треугольник"""
if a + b <= c or a + c <= b or b + c <= a:
raise ValueError("Стороны не могут образовать треугольник")

Использование пакета

# main.py
import shapes

# Использование функций из пакета
circle_area = shapes.circle_area(5)
print(f"Площадь круга с радиусом 5: {circle_area}")

rectangle_area = shapes.rectangle_area(4, 6)
print(f"Площадь прямоугольника 4x6: {rectangle_area}")

# Импорт конкретного модуля
from shapes import triangle
triangle_area = triangle.calculate_area(3, 4)
print(f"Площадь треугольника с основанием 3 и высотой 4: {triangle_area}")

# Импорт из подпакета
from shapes.utils.validator import validate_triangle_sides
try:
validate_triangle_sides(3, 4, 5)
print("Стороны 3, 4, 5 могут образовать треугольник")
except ValueError as e:
print(f"Ошибка: {e}")

Продвинутые техники

Относительный импорт

Внутри пакетов можно использовать относительные импорты:

# В файле shapes/triangle.py

# Абсолютный импорт
from shapes.utils.calculator import validate_positive

# Относительный импорт (тот же результат)
from ..utils.calculator import validate_positive

# Импорт из того же пакета
from .circle import calculate_area as circle_area

Условный импорт

# shapes/__init__.py

try:
# Попробовать импортировать numpy для более точных вычислений
import numpy as np
HAS_NUMPY = True
except ImportError:
# Использовать стандартную математику, если numpy недоступен
import math
HAS_NUMPY = False

def get_pi():
"""Возвращает значение PI в зависимости от доступных библиотек"""
if HAS_NUMPY:
return np.pi
else:
return math.pi

Динамический импорт

# Динамическая загрузка модуля
module_name = "json" # Это может быть переменной

# Способ 1: используя __import__
json_module = __import__(module_name)

# Способ 2: используя importlib (предпочтительный)
import importlib
json_module = importlib.import_module(module_name)

# Использование
data = json_module.loads('{"name": "John", "age": 30}')
print(data)

Перезагрузка модулей

import importlib
import my_module

# Если вы изменили my_module и хотите перезагрузить
my_module = importlib.reload(my_module)

Best Practices

1. Организация кода

# Хорошая структура пакета
"""
my_project/
│ README.md
│ requirements.txt
│ setup.py
└── my_package/
│ __init__.py
│ core.py
│ helpers.py
└── subpackage/
│ __init__.py
│ utils.py
└── validators.py
"""

2. Правильные имена

# Хорошие имена модулей
"""
calculator.py # Вместо calc.py
data_processor.py # Вместо dp.py
file_handler.py # Вместо fh.py
"""

3. Документирование

"""
math_operations.py

Модуль для базовых математических операций.
"""

def add(a, b):
"""
Складывает два числа.

Args:
a (float): Первое число
b (float): Второе число

Returns:
float: Сумма a и b

Examples:
>>> add(2, 3)
5
>>> add(-1, 1)
0
"""
return a + b

4. Обработка ошибок импорта

try:
import requests
except ImportError:
requests = None
print("Предупреждение: модуль requests не установлен")

def make_http_request(url):
if requests is None:
raise RuntimeError("Для использования этой функции установите requests")
return requests.get(url)

Практический проект: система управления задачами

Давайте создадим пакет для управления задачами:

task_manager/
│ __init__.py
│ task.py
│ storage.py
└── ui/
│ __init__.py
│ console.py
│ web.py

task_manager/task.py:

class Task:
def __init__(self, title, description="", priority=1):
self.title = title
self.description = description
self.priority = priority
self.completed = False

def complete(self):
self.completed = True

def __str__(self):
status = "✓" if self.completed else "✗"
return f"[{status}] {self.title} (Приоритет: {self.priority})"

task_manager/storage.py:

import json
import os

class TaskStorage:
def __init__(self, filename="tasks.json"):
self.filename = filename

def save_tasks(self, tasks):
"""Сохраняет задачи в JSON файл"""
data = []
for task in tasks:
data.append({
'title': task.title,
'description': task.description,
'priority': task.priority,
'completed': task.completed
})

with open(self.filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)

def load_tasks(self):
"""Загружает задачи из JSON файла"""
if not os.path.exists(self.filename):
return []

with open(self.filename, 'r', encoding='utf-8') as f:
data = json.load(f)

tasks = []
for item in data:
task = Task(item['title'], item['description'], item['priority'])
if item['completed']:
task.complete()
tasks.append(task)

return tasks

task_manager/ui/console.py:

class ConsoleUI:
def __init__(self, task_manager):
self.task_manager = task_manager

def show_menu(self):
"""Показывает главное меню"""
print("\n=== Менеджер задач ===")
print("1. Показать задачи")
print("2. Добавить задачу")
print("3. Завершить задачу")
print("4. Выход")

def run(self):
"""Запускает интерфейс"""
while True:
self.show_menu()
choice = input("Выберите действие: ")

if choice == '1':
self.show_tasks()
elif choice == '2':
self.add_task()
elif choice == '3':
self.complete_task()
elif choice == '4':
self.task_manager.save()
print("До свидания!")
break
else:
print("Неверный выбор!")

def show_tasks(self):
"""Показывает все задачи"""
tasks = self.task_manager.get_tasks()
if not tasks:
print("Задач нет")
return

print("\n=== Ваши задачи ===")
for i, task in enumerate(tasks, 1):
print(f"{i}. {task}")

def add_task(self):
"""Добавляет новую задачу"""
title = input("Введите название задачи: ")
description = input("Введите описание (необязательно): ")
priority = int(input("Введите приоритет (1-5): "))

self.task_manager.add_task(title, description, priority)
print("Задача добавлена!")

def complete_task(self):
"""Отмечает задачу как выполненную"""
self.show_tasks()
try:
task_num = int(input("Номер задачи для завершения: "))
self.task_manager.complete_task(task_num - 1)
print("Задача завершена!")
except (ValueError, IndexError):
print("Неверный номер задачи!")

task_manager/init.py:

from .task import Task
from .storage import TaskStorage
from .ui.console import ConsoleUI

class TaskManager:
def __init__(self, storage_file="tasks.json"):
self.storage = TaskStorage(storage_file)
self.tasks = self.storage.load_tasks()

def add_task(self, title, description="", priority=1):
"""Добавляет новую задачу"""
task = Task(title, description, priority)
self.tasks.append(task)

def get_tasks(self):
"""Возвращает все задачи"""
return self.tasks

def complete_task(self, index):
"""Отмечает задачу как выполненную"""
if 0 <= index < len(self.tasks):
self.tasks[index].complete()

def save(self):
"""Сохраняет задачи"""
self.storage.save_tasks(self.tasks)

main.py:

from task_manager import TaskManager, ConsoleUI

def main():
# Создаем менеджер задач
manager = TaskManager()

# Создаем и запускаем интерфейс
ui = ConsoleUI(manager)
ui.run()

if __name__ == "__main__":
main()

Заключение

Модули
и пакеты — это фундаментальные концепции Python, которые позволяют
создавать хорошо организованные, поддерживаемые и масштабируемые
приложения. Освоив эти инструменты, вы сможете:

  • Разбивать большие программы на логические части
  • Повторно использовать код в разных проектах
  • Создавать четкие пространства имен
  • Работать с богатой экосистемой Python-пакетов
  • Разрабатывать профессиональные приложения

Практикуйтесь
создавая собственные модули и пакеты, изучайте стандартную библиотеку
Python и популярные сторонние пакеты. Это значительно повысит вашу
эффективность как Python-разработчика!