← Назад к вопросам
Можно ли менять код фреймворка?
1.0 Junior🔥 161 комментариев
#Soft Skills#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Можно ли менять код фреймворка
Теоретически можно, но практически это плохая идея. Это один из важнейших принципов профессиональной разработки: никогда не модифицируй код зависимостей напрямую.
Почему это плохо
1. Обновления фреймворка перепишут твои изменения
# После pip install --upgrade fastapi
# Все твои изменения в site-packages/fastapi/ исчезнут
pip install --upgrade fastapi
# Твой код потерялся
2. Непредсказуемое поведение на разных машинах
# На машине разработчика: свой модифицированный код
# На production: стандартный код (обновился, переустановился)
# Результат: работает у меня, не работает на сервере
# Ад для отладки
3. Конфликты с CI/CD и контейнеризацией
# Dockerfile
FROM python:3.11
RUN pip install fastapi # Устанавливает стандартную версию
# Твои локальные изменения не будут в контейнере
4. Невозможно поделиться кодом с командой
# Ты изменил файл фреймворка
# Коллега клонирует репо — и ничего не работает
# Потому что у него стандартная версия фреймворка
Что делать вместо этого
1. Monkey Patching (если действительно нужна срочная фиксация)
# В своем коде, НЕ в коде фреймворка
from fastapi import FastAPI
from fastapi.routing import APIRoute
# Сохраняем оригинальный метод
original_operation_uses_models = APIRoute.operation_uses_models
# Переопределяем его
def patched_operation_uses_models(self):
# Твоя кастомная логика
print("Applying patch...")
return original_operation_uses_models(self)
# Применяем патч
APIRoute.operation_uses_models = patched_operation_uses_models
# Теперь все новые экземпляры APIRoute используют твой патч
app = FastAPI()
2. Наследование и расширение
# Вместо изменения fastapi.FastAPI
from fastapi import FastAPI as BaseFastAPI
from fastapi.routing import APIRoute
from typing import Optional
class MyFastApp(BaseFastAPI):
"""Расширенная версия FastAPI с кастомной логикой"""
def add_api_route(
self,
path: str,
endpoint,
**kwargs,
):
# Твоя логика перед добавлением роута
print(f"Adding route: {path}")
# Вызываем оригинальный метод
return super().add_api_route(path, endpoint, **kwargs)
# Используешь вместо FastAPI
app = MyFastApp()
@app.get("/")
def read_root():
return {"message": "Hello"}
3. Middleware и хуки
# Большинство фреймворков имеют точки расширения
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
app = FastAPI()
class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Твоя логика ДО запроса
print(f"Request: {request.url}")
response = await call_next(request)
# Твоя логика ПОСЛЕ запроса
response.headers["X-Custom-Header"] = "value"
return response
app.add_middleware(CustomMiddleware)
4. Hooks и callbacks
# Используй встроенные механизмы расширения
from fastapi import FastAPI
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# Код, выполняемый при запуске приложения
print("Application startup")
yield
# Код, выполняемый при завершении приложения
print("Application shutdown")
app = FastAPI(lifespan=lifespan)
5. Dependency Injection
# Большинство фреймворков поддерживают DI
from fastapi import FastAPI, Depends
from typing import Annotated
class CustomLogger:
def log(self, msg: str):
print(f"[LOG] {msg}")
logger = CustomLogger()
async def get_logger() -> CustomLogger:
return logger
app = FastAPI()
@app.get("/")
async def read_root(logger: Annotated[CustomLogger, Depends(get_logger)]):
logger.log("Root endpoint called")
return {"message": "Hello"}
6. Конфигурация и переменные окружения
# Вместо изменения фреймворка — используй конфиг
from fastapi import FastAPI
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "MyApp"
custom_header: str = "default"
debug: bool = False
class Config:
env_file = ".env"
settings = Settings()
app = FastAPI(title=settings.app_name, debug=settings.debug)
@app.get("/")
def read_root():
return {"header": settings.custom_header}
7. Создание своего микрофреймворка
Если фреймворк сильно не подходит, лучше написать свой обертка:
# myframework.py — твой обертка
from fastapi import FastAPI as BaseFastAPI
from fastapi.routing import APIRoute
class MyFramework(BaseFastAPI):
"""Обертка над FastAPI с кастомной логикой"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._init_custom_stuff()
def _init_custom_stuff(self):
# Инициализация твоих кастомных компонентов
pass
def custom_route(self, *args, **kwargs):
# Твой кастомный декоратор
def decorator(func):
# Твоя логика
return self.get(*args, **kwargs)(func)
return decorator
# Используется как обычно
app = MyFramework()
@app.custom_route("/")
def read_root():
return {"message": "Hello"}
Когда нужно изменять фреймворк (редко)
Сценарий 1: Фиксим критический баг
# 1. Сообщаем разработчикам фреймворка (issue)
# 2. Используем патч из их репо
# 3. Если срочно нужно:
# requirements.txt
fastapi @ git+https://github.com/myusername/fastapi@bugfix-branch
# или локальный патч
fastapi @ file:///path/to/local/fastapi
Сценарий 2: Форк фреймворка
# Только если:
# 1. Фреймворк не поддерживается
# 2. Нужны серьезные изменения
# 3. Готов поддерживать форк
git clone https://github.com/fastapi/fastapi.git
git checkout -b my-fork
# Твои изменения
git push origin my-fork
# requirements.txt
fastapi @ git+https://github.com/myusername/fastapi@my-fork
Лучшие практики
- Не трогай site-packages — никогда
- Используй механизмы расширения фреймворка — middleware, hooks, callbacks
- Наследуй и расширяй — создавай свои классы на основе фреймворка
- Monkey patch только в своем коде — если критично
- Форк только в крайнем случае — потом будет сложно мержить
- Пропоси фичу в проект — если нужно что-то большое
- Документируй расширения — чтобы команда поняла кастомизацию
Аналогия
# Плохо: менять Django в site-packages
vi /path/to/venv/lib/python3.11/site-packages/django/db/models/base.py
# Хорошо: расширить модели Django
from django.db import models
class MyModel(models.Model):
# Твоя логика
pass
Вывод
Менять код фреймворка можно технически, но это антипаттерн. Всегда есть правильный способ расширить фреймворк через его API: наследование, middleware, hooks, конфигурация, зависимости. Если фреймворк не позволяет расширяться нужным тебе способом — подумай, правильный ли выбран фреймворк.