_CORE
AI & Agentic Systems Core Information Systems Cloud & Platform Engineering Data Platform & Integration Security & Compliance QA, Testing & Observability IoT, Automation & Robotics Mobile & Digital Banking & Finance Insurance Public Administration Defense & Security Healthcare Energy & Utilities Telco & Media Manufacturing Logistics & E-commerce Retail & Loyalty
References Technologies Blog Know-how Tools
About Collaboration Careers
CS EN
Let's talk

Python in Production: Architecture, Performance and Best Practices for 2026

20. 02. 2026 6 min read CORE SYSTEMSSoftware Engineering
Python in Production: Architecture, Performance and Best Practices for 2026

Python in Production: Architecture, Performance and Best Practices for 2026

Python dominates in AI/ML, data engineering, automation and backend development. But moving from a Jupyter notebook to production requires discipline. This guide summarises proven approaches for 2026.

Production Python Project Architecture

my-project/
├── src/
│   └── myproject/
│       ├── __init__.py          # Version, public API
│       ├── core/                # Business logic (pure Python)
│       │   ├── models.py        # Dataclasses, Pydantic models
│       │   ├── engine.py        # Core computation logic
│       │   └── validators.py    # Validation, constraints
│       ├── adapters/            # I/O (DB, API, files)
│       │   ├── database.py
│       │   ├── api_client.py
│       │   └── file_handler.py
│       ├── services/            # Orchestration (links core + adapters)
│       │   └── pipeline.py
│       └── cli/                 # CLI interface
│           └── main.py
├── tests/
│   ├── unit/                    # Fast, isolated
│   ├── integration/             # With external dependencies
│   └── conftest.py
├── pyproject.toml               # Single configuration file
├── Dockerfile
├── Makefile
└── README.md

Key Principles

  1. Separate I/O from logiccore/ has no imports from external services
  2. Dependency injection — adapters are passed as parameters, not global imports
  3. Dataclasses everywhere — typed data structures instead of dicts
  4. Single entry point — CLI or API, never both in one module

Typing — Necessity, Not Luxury

Python 3.12+ brings a mature type system. In 2026, untyped code does not belong in production.

from dataclasses import dataclass
from typing import Optional, Protocol
from collections.abc import Sequence


# Dataclass instead of dict
@dataclass(frozen=True, slots=True)
class TradeSignal:
    symbol: str
    direction: float  # -1.0 to 1.0
    strength: float   # 0.0 to 1.0
    strategy: str
    timestamp: str

    def __post_init__(self):
        if not -1 <= self.direction <= 1:
            raise ValueError(f"direction must be [-1, 1], got {self.direction}")
        if not 0 <= self.strength <= 1:
            raise ValueError(f"strength must be [0, 1], got {self.strength}")


# Protocol instead of ABC (structural typing)
class DataFetcher(Protocol):
    def fetch_ohlcv(self, symbol: str, timeframe: str, limit: int) -> list[dict]: ...
    def fetch_ticker(self, symbol: str) -> dict: ...


# Generic functions with precise types
def combine_signals(
    signals: Sequence[TradeSignal],
    weights: Optional[dict[str, float]] = None,
) -> TradeSignal:
    """Combines signals from multiple strategies."""
    if not signals:
        raise ValueError("No signals to combine")

    total_weight = 0.0
    weighted_dir = 0.0

    for sig in signals:
        w = (weights or {}).get(sig.strategy, 1.0)
        weighted_dir += sig.direction * sig.strength * w
        total_weight += w

    avg_direction = weighted_dir / total_weight if total_weight > 0 else 0.0

    return TradeSignal(
        symbol=signals[0].symbol,
        direction=max(-1.0, min(1.0, avg_direction)),
        strength=abs(avg_direction),
        strategy="ensemble",
        timestamp=signals[0].timestamp,
    )

Typing Toolchain

Tool Purpose Recommendation
mypy Static type checker --strict mode in CI
pyright Faster alternative VS Code integration
Pydantic v2 Runtime validation + serialisation For API models
beartype Runtime type checking (decorator) For critical paths
# pyproject.toml — mypy strict mode
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

Performance — Python Doesn’t Have to Be Slow

NumPy/Pandas Vectorisation

# ❌ Slow — Python loop
def slow_moving_average(prices: list[float], window: int) -> list[float]:
    result = []
    for i in range(len(prices)):
        if i < window:
            result.append(float('nan'))
        else:
            result.append(sum(prices[i-window:i]) / window)
    return result

# ✅ Fast — NumPy vectorisation (100–1000× faster)
import numpy as np

def fast_moving_average(prices: np.ndarray, window: int) -> np.ndarray:
    cumsum = np.cumsum(np.insert(prices, 0, 0))
    return (cumsum[window:] - cumsum[:-window]) / window

Profiling and Optimisation

# cProfile to identify bottlenecks
python -m cProfile -s cumtime my_script.py

# line_profiler for line-level analysis
kernprof -l -v my_script.py

# memory_profiler for memory leaks
python -m memory_profiler my_script.py

When to Reach for C Extensions

Situation Solution
Numerical computation NumPy, SciPy (already in C)
Custom hot loop numba JIT compilation
Data transformations Polars (Rust backend)
Parallelism multiprocessing, concurrent.futures
I/O bound asyncio, httpx
Truly critical Cython, PyO3 (Rust)
# Numba — JIT compilation for numerical code
from numba import njit

@njit
def fast_ewma(data: np.ndarray, alpha: float) -> np.ndarray:
    result = np.empty_like(data)
    result[0] = data[0]
    for i in range(1, len(data)):
        result[i] = alpha * data[i] + (1 - alpha) * result[i-1]
    return result

Testing — Pyramid, Not Iceberg

         /\
        /  \   E2E (5%)
       /    \
      / Integ \ Integration (15%)
     /  ration  \
    /____________\
   /   Unit Tests  \  Unit (80%)
  /________________\
# conftest.py — fixtures for dependency injection
import pytest
from unittest.mock import AsyncMock

@pytest.fixture
def mock_fetcher():
    fetcher = AsyncMock()
    fetcher.fetch_ohlcv.return_value = [
        {"open": 100, "high": 105, "low": 98, "close": 103, "volume": 1000}
    ]
    return fetcher

@pytest.fixture
def engine(mock_fetcher):
    from myproject.core.engine import TradingEngine
    return TradingEngine(fetcher=mock_fetcher)


# test_engine.py — clean unit tests
def test_signal_generation(engine):
    signal = engine.generate_signal("BTC/USDT")
    assert -1 <= signal.direction <= 1
    assert 0 <= signal.strength <= 1


# Parametrized tests
@pytest.mark.parametrize("direction,expected", [
    (0.8, "long"),
    (-0.8, "short"),
    (0.1, "flat"),
])
def test_signal_action(direction, expected):
    assert signal_to_action(direction, threshold=0.3) == expected

CI Pipeline

# GitHub Actions
name: CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pip install -e ".[dev]"
      - run: mypy src/ --strict
      - run: ruff check src/ tests/
      - run: pytest tests/ -v --cov=src --cov-report=xml
      - run: pytest tests/integration/ -v -m integration

Packaging — pyproject.toml Is the Standard

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my-trading-framework"
version = "0.3.0"
description = "Quantitative trading framework"
requires-python = ">=3.11"
dependencies = [
    "numpy>=1.26",
    "pandas>=2.1",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "mypy>=1.8",
    "ruff>=0.2",
    "pytest-cov",
]
exchange = [
    "ccxt>=4.0",
]

[tool.ruff]
target-version = "py312"
line-length = 100
select = ["E", "F", "I", "UP", "B", "SIM"]

[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
    "integration: marks tests requiring external services",
]

Deployment

Docker Multi-Stage Build

# Build stage
FROM python:3.12-slim AS builder
WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir build && \
    pip wheel --no-cache-dir --wheel-dir /wheels -e ".[exchange]"

# Runtime stage
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/*.whl && rm -rf /wheels
COPY src/ src/
USER nobody
CMD ["python", "-m", "myproject.cli.main"]

Production Monitoring

import structlog
import time
from functools import wraps

logger = structlog.get_logger()

def monitor(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        try:
            result = func(*args, **kwargs)
            duration = time.perf_counter() - start
            logger.info("function_completed",
                function=func.__name__,
                duration_ms=round(duration * 1000, 2),
            )
            return result
        except Exception as e:
            duration = time.perf_counter() - start
            logger.error("function_failed",
                function=func.__name__,
                error=str(e),
                duration_ms=round(duration * 1000, 2),
            )
            raise
    return wrapper

Conclusion

Production Python in 2026 requires:

  1. Strict typing — mypy strict in CI, dataclasses everywhere
  2. Clean architecture — separate I/O from logic
  3. Vectorisation — NumPy/Polars for numerical operations
  4. Quality automation — ruff + mypy + pytest on every commit
  5. Containerisation — multi-stage Docker, nobody user

Python remains the dominant language for data and AI. With discipline, it’s ready for mission-critical production systems too.


Need help with your Python application architecture? Contact us for a consultation.

pythonarchitectureproductionperformancebest-practicestyping
Share:

CORE SYSTEMS

Stavíme core systémy a AI agenty, které drží provoz. 15 let zkušeností s enterprise IT.

Need help with implementation?

Our experts can help with design, implementation, and operations. From architecture to production.

Contact us