Разбивка кода на файлы — зачем и как
Вы написали 2000 строк в одном файле main.py. Поздравляем — вы только что создали себе головную боль на годы вперёд. В этом уроке разберёмся, почему один большой файл — это проблема, и как правильно организовать код по файлам.
😰 Представьте: 2000 строк в одном файле
Когда вы только начинаете программировать, всё кажется просто: создал файл main.py, написал туда весь код, запустил — работает. Отлично!
Но проект растёт. Появляются новые классы, функции, константы. Файл набухает: сначала 200 строк, потом 500, потом 1000, 2000... И вот здесь начинается настоящий кошмар.
📖 Аналогия: книга без глав
Представьте книгу на 600 страниц — без оглавления, без глав, без разделов. Просто сплошной текст от начала до конца. Вы хотите найти место, где говорится про главного героя во второй части. Удачи вам в поиске! Именно так ощущается работа с «монолитным» файлом кода.
🏠 Аналогия: квартира без комнат
Или представьте квартиру — огромный зал без стен и перегородок. В одном углу спят, в другом готовят, в третьем работают, посередине стоит диван, рядом — холодильник, стиральная машина и письменный стол. Всё в одном пространстве. Неудобно? Так же неудобно работать с кодом, где классы, функции, конфигурация и тесты свалены в один файл.
Разберём конкретные боли, которые появляются с ростом файла:
🔍
Поиск нужного места
«Где у меня класс User? На какой строке функция calculate_price?» Ctrl+F по файлу на 2000 строк — не самое приятное занятие.
🤝
Работа в команде
Вы оба с коллегой работаете над main.py. Каждый раз при слиянии (merge) в git — конфликты. Один файл не может редактировать два человека без столкновений.
😵
Понимание кода
Через три месяца вы открываете свой же файл и не помните, что там написано. Когда всё смешано — очень сложно удержать в голове, что к чему относится.
♻️
Переиспользование
Вы написали отличную функцию для другого проекта. Но забрать её нельзя — она зарыта среди 2000 строк и зависит от всего остального кода вокруг.
🚨 Главная боль монолитного файла — это не то, что компьютеру тяжело его выполнять. Компьютеру всё равно. Боль в том, что с таким кодом мучаются люди: вы сами через месяц, ваши коллеги, все кто будет поддерживать этот код.
💡 Главная мысль: разбивка кода — это про людей
Прежде чем идти дальше, запомните одну фундаментальную вещь:
Код читают люди.
Компьютер выполняет байт-код — ему всё равно, как вы назвали файлы и разложили классы.
Когда вы разбиваете проект на файлы — вы создаёте структуру для людей. Каждый файл — это отдельная «тема», отдельная «глава книги». Открыв файл models/user.py, любой разработчик мгновенно понимает: здесь живёт всё, что связано с пользователями.
Хорошо структурированный проект — это проявление уважения к другим людям (и к себе будущему). Это профессиональный навык, который отличает джуниора от мидла.
🌱 Принцип единственной ответственности (Single Responsibility): каждый файл, каждый класс, каждая функция должны делать одну вещь и делать её хорошо. Один файл — одна тема. Это делает код понятным, тестируемым и переиспользуемым.
📁 До и после: структура проекта
Рассмотрим конкретный пример. Допустим, вы пишете простой интернет-магазин. Вот как выглядит типичный «монолитный» подход и правильная структура:
❌ До: всё в одном файле
shop/
└── main.py ← 2347 строк
# строки 1-50: импорты
# строки 51-200: класс User
# строки 201-400: класс Product
# строки 401-500: класс Cart
# строки 501-700: класс Order
# строки 701-900: функции работы с БД
# строки 901-1100: функции отправки email
# строки 1101-1400: расчёт доставки
# строки 1401-1700: API-эндпоинты
# строки 1701-2000: утилиты и хелперы
# строки 2001-2347: тесты (!!!)
✅ После: логическая структура
shop/
├── main.py ← 30 строк (точка входа)
├── models/
│ ├── user.py ← класс User
│ ├── product.py ← класс Product
│ ├── cart.py ← класс Cart
│ └── order.py ← класс Order
├── services/
│ ├── database.py ← работа с БД
│ ├── email.py ← отправка писем
│ └── delivery.py ← расчёт доставки
├── api/
│ └── endpoints.py ← API-эндпоинты
├── utils/
│ └── helpers.py ← утилиты
└── tests/
├── test_user.py
└── test_order.py
Видите разницу? Во втором случае, чтобы найти класс User, не нужно ничего искать — вы сразу открываете models/user.py. Хотите исправить расчёт доставки? services/delivery.py. Всё логично и предсказуемо.
🗂️ Принцип хорошей структуры: человек, видящий ваш проект впервые, должен за 10 секунд понять, где что лежит. Если структура требует объяснений — она недостаточно хороша.
🧩 Логическая группировка: каждый файл — одна тема
Как решить, что положить в какой файл? Задайте себе вопрос: «О чём этот код?»
Код, который отвечает на один и тот же вопрос, должен жить вместе. Несколько практических правил:
📦 Модели данных → папка models/
Классы, которые описывают ваши данные: User, Product, Order. Каждый класс — свой файл. Файл называется так же, как класс, только в нижнем регистре.
⚙️ Бизнес-логика → папка services/
Функции, которые «делают что-то»: считают цену, отправляют письма, обращаются к базе данных. Это сервисы — логика работы приложения.
🔧 Вспомогательные функции → папка utils/
Небольшие «инструменты», которые используются везде: форматирование даты, валидация email, генерация ID. Не относятся ни к одной конкретной теме, но нужны всем.
🧪 Тесты → папка tests/
Тесты всегда отдельно от основного кода! И структура папки tests/ обычно зеркалит структуру основного проекта: есть models/user.py — значит, есть и tests/test_user.py.
Вот как выглядит маленький учебный проект — магазин с тремя классами, разбитый по файлам:
my_shop/
├── main.py ← запускаем отсюда
├── models/
│ ├── __init__.py ← пустой файл, делает папку пакетом Python
│ ├── product.py ← класс Product
│ └── cart.py ← класс Cart
└── utils/
├── __init__.py
└── formatters.py ← вспомогательные функции
Заметили файлы __init__.py? Это специальные пустые файлы, которые говорят Python: «эта папка — пакет, из неё можно импортировать». Без них Python не увидит папку как место, откуда можно делать import. Подробнее разберём в следующем уроке.
👀 Читаемость: проще найти нужный класс
Представьте: продакт-менеджер говорит вам: «Нужно добавить скидку к продукту». Где вы будете делать изменения?
❌ Монолитный проект
Открываем main.py — 2000 строк. Ищем class Product... Ctrl+F, нашли на строке 247. Вносим изменение. А подождите, тут же рядом 50 строк, которые непонятно к чему относятся. Осторожно, не сломать бы что-то ещё...
✅ Правильная структура
Открываем models/product.py — 80 строк, и только class Product. Находим нужное место моментально, добавляем поле discount. В этом файле нет ничего лишнего, всё относится только к продукту. Спокойно, без страха.
Маленький файл с одной темой — это фокус внимания. Когда вы открываете models/product.py, вы точно знаете: всё, что здесь есть, связано с продуктом. Больше ничего. Это снижает когнитивную нагрузку и уменьшает риск ошибок.
🎯 Правило: если в файле больше 200–300 строк и он касается разных тем — это сигнал, что его пора разбить. Конечно, это не жёсткое правило, но хороший ориентир для начинающих.
👥 Командная разработка: разные люди — разные файлы
Программирование в реальных компаниях — это командная работа. Над одним проектом могут одновременно работать 5, 10, 50 человек. И здесь структура проекта становится критически важной.
Рассмотрим ситуацию с системой контроля версий git — инструментом, который отслеживает изменения в коде и помогает команде работать вместе:
❌ Проблема с одним файлом
Катя работает над классом User в main.py (строки 50–200). Коля одновременно работает над классом Product в том же main.py (строки 201–400). Оба сохраняют изменения в git.
Результат: конфликт при слиянии (merge conflict). Git не понимает, чьи изменения правильные, потому что оба изменили один и тот же файл. Придётся вручную разбираться, какие строки оставить — и это отнимает время, нервы и создаёт риск ошибок.
✅ Решение с правильной структурой
Катя работает в models/user.py. Коля работает в models/product.py. Это разные файлы — git без проблем сливает их изменения автоматически, без конфликтов. Оба могут работать параллельно, не мешая друг другу.
👨💻 На практике: в больших компаниях принято, что каждый разработчик «владеет» своей областью кода. Один отвечает за модели, другой — за API, третий — за тесты. Правильная структура файлов делает эту «границу ответственности» очевидной и чёткой.
♻️ Переиспользование: модуль в другом проекте
Ещё одно мощное преимущество хорошей структуры — возможность использовать код повторно.
Представьте: вы написали отличные утилиты для работы с датами — format_date(), days_between(), is_weekend(). Потом начинаете новый проект и понимаете, что те же функции нужны здесь тоже.
❌ Монолитный main.py
Функции зарыты в середине 2000 строк. Чтобы их забрать, нужно аккуратно вырезать нужные части, проверить что они не зависят от другого кода вокруг... Скорее всего, они зависят — и придётся тянуть ещё половину файла.
✅ Файл utils/dates.py
Все функции для дат живут в одном файле и зависят только друг от друга. Просто скопируйте dates.py в новый проект и напишите from utils.dates import format_date. Готово!
Именно так работают популярные библиотеки Python — requests, pandas, numpy. Каждая из них — это набор хорошо организованных файлов с чёткими темами. Вы просто пишете import requests и получаете доступ к сотням функций.
🚀 Мечта разработчика: написал модуль один раз — используешь в десяти проектах. Это возможно только если код хорошо изолирован в отдельных файлах с чёткими зависимостями.
💻 Как это выглядит в коде
Давайте посмотрим на конкретный пример. Возьмём небольшой проект магазина и разобьём его по файлам. Всё, что нужно знать об import — разберём в следующем уроке, сейчас просто смотрите на структуру.
Файл models/product.py — только о продукте:
# models/product.py
# Этот файл знает только об одном: что такое Product
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def apply_discount(self, percent):
"""Применить скидку в процентах"""
self.price = self.price * (1 - percent / 100)
def __str__(self):
return f"{self.name} — {self.price:.2f} руб."
Файл models/cart.py — только о корзине:
# models/cart.py
# Этот файл знает только об одном: что такое Cart
from models.product import Product # берём Product из соседнего файла
class Cart:
def __init__(self):
self.items = []
def add(self, product):
self.items.append(product)
def total(self):
return sum(item.price for item in self.items)
def __str__(self):
lines = [str(item) for item in self.items]
lines.append(f"Итого: {self.total():.2f} руб.")
return "\n".join(lines)
Файл main.py — только точка входа, минимум кода:
# main.py
# Точка входа в программу — только запускает и соединяет части
from models.product import Product
from models.cart import Cart
# Создаём продукты
apple = Product("Яблоко", 50)
banana = Product("Банан", 30)
apple.apply_discount(10) # скидка 10%
# Собираем корзину
cart = Cart()
cart.add(apple)
cart.add(banana)
print(cart)
# Яблоко — 45.00 руб.
# Банан — 30.00 руб.
# Итого: 75.00 руб.
✨ Обратите внимание: main.py стал чистым и коротким. Он просто «собирает» компоненты вместе. Каждый модуль делает своё дело. Хотите изменить логику корзины? Открываете models/cart.py — и только его.
📐 Принципы хорошей структуры проекта
Запомните несколько простых правил, которые помогут вам организовать код правильно:
Один файл — одна тема
Файл product.py содержит только код, относящийся к продуктам. Никаких «заодно положу сюда ещё функцию для отправки email».
Имена файлов должны говорить сами за себя
user.py, email_sender.py, price_calculator.py — из названия понятно содержимое. stuff.py, misc.py, utils2.py — плохие имена.
Группируйте по смыслу, а не по типу
Лучше папка orders/ со всем, что связано с заказами, чем папка classes/ со всеми классами проекта. Папки отражают области задач, не технические категории.
Не дробите слишком мелко
Файл на 10 строк с одной функцией — перебор. Если несколько связанных функций вместе занимают 50 строк, им хорошо в одном файле. Цель — читаемость, не максимальное количество файлов.
main.py — только точка входа
Файл main.py (или app.py) должен быть коротким. Его задача — запустить приложение, собрав части вместе. Вся логика — в модулях.
✅ Итоги урока
- Монолитный файл на 2000 строк — это не проблема для компьютера, это проблема для людей: сложно искать, страшно менять, невозможно работать в команде без конфликтов.
- Разбивка по файлам — это про читаемость, сопровождение и командную работу. Компьютеру всё равно, люди скажут спасибо.
- Каждый файл — одна тема:
user.pyо пользователях,cart.pyо корзине,email.pyоб отправке писем. Название файла = тема файла. - Git и команда: разные люди работают с разными файлами — нет конфликтов при слиянии, каждый знает свою область.
- Переиспользование: изолированный модуль легко перенести в другой проект — просто скопируй файл и импортируй.
main.pyдолжен быть коротким — только точка входа, которая собирает компоненты вместе.
👉 В следующем уроке мы разберём механику Python-модулей: что такое import, как Python ищет файлы, зачем нужен __init__.py, и как правильно импортировать классы из других файлов. Теория закончилась — начнём писать код с нуля в нескольких файлах.