Привет! Сегодня мы окунемся в мир ORM — Object-Relational Mapping. Звучит как заклинание, да? На деле, всё проще: ORM позволяет работать с базой данных, как будто вы работаете с обычными объектами Python. Больше никаких SQL-запросов, только чистый, приятный код. Давайте разберемся, как это работает и чем нам это может помочь.
Представьте, вы пишете блог (как я!) и хотите хранить информацию о статьях: заголовок, текст, дату публикации. Можно, конечно, вручную конструировать SQL-запросы, трекать подключения к базе, писать конвертацию типов. А можно — просто использовать ORM, например, SQLAlchemy или Peewee.
Начнем с SQLAlchemy — одного из самых популярных вариантов.
Устанавливаем:
Создадим простое приложение:
Готово! Мы только что:
- Создали таблицу в SQLite без единого SQL-запроса
- Вставили новую запись в базу данных
- Использовали объектно-ориентированный подход
Если вы знакомы с Django, то знаете, что у него свой встроенный ORM — возможно, один из лучших для быстрого старта. Но если вы хотите легковесность и контроль — SQLAlchemy и Peewee (более минималистичный вариант) вас приятно удивят.
Для сравнения — как выглядит чтение данных:
Или обновление:
Да, ORM не избавляет от необходимости думать о данных, транзакциях и индексации. Но он делает код чище, безопаснее и легче в сопровождении.
Совет: используйте ORM везде, где важна читаемость и масштабируемость проекта. Особенно, если вы работаете в команде — структура кода будет единообразной, и новому участнику будет проще разобраться.
В следующий раз расскажу, как связать несколько таблиц и делать отношения "один-ко-многим" в ORM-стиле. А пока — протестируйте код выше, поэкспериментируйте. Ведь лучший способ выучить ORM — начать его действительно использовать!
Представьте, вы пишете блог (как я!) и хотите хранить информацию о статьях: заголовок, текст, дату публикации. Можно, конечно, вручную конструировать SQL-запросы, трекать подключения к базе, писать конвертацию типов. А можно — просто использовать ORM, например, SQLAlchemy или Peewee.
Начнем с SQLAlchemy — одного из самых популярных вариантов.
Устанавливаем:
pip install sqlalchemy
Создадим простое приложение:
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.orm import declarative_base, sessionmaker
from datetime import datetime
Base = declarative_base()
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String)
content = Column(String)
published_at = Column(DateTime, default=datetime.utcnow)
# Настраиваем соединение с SQLite
engine = create_engine('sqlite:///blog.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Создаем и сохраняем пост
new_post = Post(title="My First ORM Post", content="ORMs make life easier!")
session.add(new_post)
session.commit()
Готово! Мы только что:
- Создали таблицу в SQLite без единого SQL-запроса
- Вставили новую запись в базу данных
- Использовали объектно-ориентированный подход
Если вы знакомы с Django, то знаете, что у него свой встроенный ORM — возможно, один из лучших для быстрого старта. Но если вы хотите легковесность и контроль — SQLAlchemy и Peewee (более минималистичный вариант) вас приятно удивят.
Для сравнения — как выглядит чтение данных:
posts = session.query(Post).filter(Post.title.like("%ORM%")).all()
for post in posts:
print(post.title, post.published_at)
Или обновление:
post = session.query(Post).first()
post.title = "Updated title"
session.commit()
Да, ORM не избавляет от необходимости думать о данных, транзакциях и индексации. Но он делает код чище, безопаснее и легче в сопровождении.
Совет: используйте ORM везде, где важна читаемость и масштабируемость проекта. Особенно, если вы работаете в команде — структура кода будет единообразной, и новому участнику будет проще разобраться.
В следующий раз расскажу, как связать несколько таблиц и делать отношения "один-ко-многим" в ORM-стиле. А пока — протестируйте код выше, поэкспериментируйте. Ведь лучший способ выучить ORM — начать его действительно использовать!
👍1
🔥 Как асинхронное программирование улучшает производительность сетевых приложений?
Если вы уже писали на Python сетевые приложения — например, телеграм-бота, простенький HTTP-сервер или парсер сайтов — вы, скорее всего, сталкивались с тем, что программа "зависает", когда ждет ответа от сервера. В этот момент Python… просто сидит и ждет. Чай себе заваривает. А вы — греете процессор на холостом ходу.
Но можно по-другому. Асинхронно. И вот в тот момент, когда вы впервые запускаете свой async-код и видите, как он в разы быстрее перебирает запросы, возникает ощущение магии. На самом деле, никакой магии — просто асинхронность.
🧠 Что происходит в обычной программе?
Вот пример кода, написанного "по старинке":
Каждый запрос “зависает” на 2 секунды (сайт задерживает выдачу ответа). Всего уходит около 10 секунд. Никакой многозадачности — каждая следующая итерация ждет завершения предыдущей.
📈 А теперь асинхронный подход:
Вся пятерка запросов отрабатывает… параллельно!
⏱ Результат? Вместо 10 секунд — примерно 2 секунды. Гениально просто.
⚙️ Почему это работает?
Асинхронная модель основана на событийном цикле. Когда вы делаете операцию ввода-вывода — например, ждете данные из интернета — интерпретатор Python освобождает поток и занимается другими задачами. Этот подход отлично работает, когда операций ввода-вывода много, а процессор почти не загружен — типичная ситуация для сетевых приложений.
Монолитный
💥 Где использовать асинхронность?
- Боты и чат-приложения (async-сервер получает и отправляет сообщения без задержек)
- Web API-клиенты (одновременно дергаем десятки API)
- Парсеры сайтов (асинхронный скачиватель страниц)
- Веб-серверы (FastAPI и aiohttp прекрасно работают в async-режиме)
☝️ Важно понимать: асинхронность — это не многопоточность. Она не ускорит вашу математику или генерацию изображений. Но она незаменима там, где приложение тратит время на ожидание.
🎯 Вывод
Асинхронное программирование в Python — это не роскошь, а инструмент оптимизации. Особенно в сетевых задачах, где каждый миллисекундный выигрыш ускоряет приложение многократно.
Python дает вам отличные async-инструменты прямо из коробки:
Если вы уже писали на Python сетевые приложения — например, телеграм-бота, простенький HTTP-сервер или парсер сайтов — вы, скорее всего, сталкивались с тем, что программа "зависает", когда ждет ответа от сервера. В этот момент Python… просто сидит и ждет. Чай себе заваривает. А вы — греете процессор на холостом ходу.
Но можно по-другому. Асинхронно. И вот в тот момент, когда вы впервые запускаете свой async-код и видите, как он в разы быстрее перебирает запросы, возникает ощущение магии. На самом деле, никакой магии — просто асинхронность.
🧠 Что происходит в обычной программе?
Вот пример кода, написанного "по старинке":
import requests
def fetch_data():
response = requests.get('https://httpbin.org/delay/2')
return response.text
for _ in range(5):
print(fetch_data())
Каждый запрос “зависает” на 2 секунды (сайт задерживает выдачу ответа). Всего уходит около 10 секунд. Никакой многозадачности — каждая следующая итерация ждет завершения предыдущей.
📈 А теперь асинхронный подход:
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, 'https://httpbin.org/delay/2') for _ in range(5)]
results = await asyncio.gather(*tasks)
for r in results:
print(r)
asyncio.run(main())
Вся пятерка запросов отрабатывает… параллельно!
aiohttp
и asyncio
позволяют не простаивать в ожидании ответа, а запускать другие задачи.⏱ Результат? Вместо 10 секунд — примерно 2 секунды. Гениально просто.
⚙️ Почему это работает?
Асинхронная модель основана на событийном цикле. Когда вы делаете операцию ввода-вывода — например, ждете данные из интернета — интерпретатор Python освобождает поток и занимается другими задачами. Этот подход отлично работает, когда операций ввода-вывода много, а процессор почти не загружен — типичная ситуация для сетевых приложений.
Монолитный
requests
и другие синхронные библиотеки всегда блокируют выполнение, пока не получат результат. Async дает экономию времени, когда у вас десятки, сотни запросов, и каждый из них можно запускать одновременно.💥 Где использовать асинхронность?
- Боты и чат-приложения (async-сервер получает и отправляет сообщения без задержек)
- Web API-клиенты (одновременно дергаем десятки API)
- Парсеры сайтов (асинхронный скачиватель страниц)
- Веб-серверы (FastAPI и aiohttp прекрасно работают в async-режиме)
☝️ Важно понимать: асинхронность — это не многопоточность. Она не ускорит вашу математику или генерацию изображений. Но она незаменима там, где приложение тратит время на ожидание.
🎯 Вывод
Асинхронное программирование в Python — это не роскошь, а инструмент оптимизации. Особенно в сетевых задачах, где каждый миллисекундный выигрыш ускоряет приложение многократно.
Python дает вам отличные async-инструменты прямо из коробки:
asyncio
, aiohttp
, FastAPI
, httpx
и другие. Освоив их однажды, вы больше никогда не захотите возвращаться к бесконечным “зависаниям”.🔥1
Если тебе когда-нибудь хотелось создать веб-приложение для анализа данных — и при этом не хочется влезать в мир JavaScript, HTML и CSS — то ты попал по адресу. Сегодня я расскажу про Plotly Dash: мощный инструмент для построения интерактивных аналитических приложений, полностью на Python. Звучит как магия? Это потому, что почти так и есть.
Plotly Dash — это библиотека на Python, которая позволяет создавать веб-приложения для визуализации и анализа данных с помощью кода, который выглядит как обычный скрипт. Без необходимости знать фронтенд. Интерфейс строится на основе компонент React, но всё спрятано под капотом — ты просто создаёшь layout и указываешь логику в виде Python-функций.
Рассмотрим простейший пример.
Допустим, нам нужно создать дашборд, который показывает, как меняется синусоида в зависимости от частоты, которую выбирает пользователь. Для этого нам нужно установить Dash:
Теперь код приложения:
Это полноценное веб-приложение. На странице пользователь может регулировать ползунок, меняющий частоту синусоиды, и график будет обновляться в реальном времени. Всё это — с минимальным количеством кода.
Dash особенно мощен, когда тебе нужно построить интерактивные фильтры данных, таблицы, выпадающие списки, вкладки, загрузку CSV-файлов — для всего этого уже есть готовые компоненты. Соединение Plotly (интерактивные графики) и Dash (веб-интерфейс плюс логика) делает библиотеку отличным выбором для Data Science.
Дополнительно Dash легко разворачивается на Heroku, Render или любой другой платформе с поддержкой Python. А значит, ты можешь делать прототипы, MVP и небольшие демонстрационные проекты без громоздких фреймворков.
Совет от меня: начни с чего-то простого. Например, загрузка CSV-файла и построение графика по выбранным колонкам. Это поможет понять принципы связи layout-компонентов и callback-функций. А дальше — хоть предиктивная аналитика с машинным обучением!
Dash не заменит тебе полноценную веб-разработку, но если ты Python-разработчик, которому нужно быстро визуализировать данные — это просто находка.
Plotly Dash — это библиотека на Python, которая позволяет создавать веб-приложения для визуализации и анализа данных с помощью кода, который выглядит как обычный скрипт. Без необходимости знать фронтенд. Интерфейс строится на основе компонент React, но всё спрятано под капотом — ты просто создаёшь layout и указываешь логику в виде Python-функций.
Рассмотрим простейший пример.
Допустим, нам нужно создать дашборд, который показывает, как меняется синусоида в зависимости от частоты, которую выбирает пользователь. Для этого нам нужно установить Dash:
pip install dash
Теперь код приложения:
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import numpy as np
import plotly.graph_objs as go
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("Dynamic Sine Wave Plot"),
dcc.Slider(
id='frequency-slider',
min=1,
max=10,
step=0.5,
value=1,
marks={i: str(i) for i in range(1, 11)}
),
dcc.Graph(id='sine-graph')
])
@app.callback(
Output('sine-graph', 'figure'),
Input('frequency-slider', 'value')
)
def update_graph(frequency):
x_vals = np.linspace(0, 2 * np.pi, 500)
y_vals = np.sin(frequency * x_vals)
figure = go.Figure(
data=[
go.Scatter(x=x_vals, y=y_vals, mode='lines', name='Sine Wave')
],
layout=go.Layout(
title=f"Sine Wave with Frequency {frequency}",
xaxis={'title': 'x'},
yaxis={'title': 'sin(f*x)'}
)
)
return figure
if __name__ == '__main__':
app.run_server(debug=True)
Это полноценное веб-приложение. На странице пользователь может регулировать ползунок, меняющий частоту синусоиды, и график будет обновляться в реальном времени. Всё это — с минимальным количеством кода.
Dash особенно мощен, когда тебе нужно построить интерактивные фильтры данных, таблицы, выпадающие списки, вкладки, загрузку CSV-файлов — для всего этого уже есть готовые компоненты. Соединение Plotly (интерактивные графики) и Dash (веб-интерфейс плюс логика) делает библиотеку отличным выбором для Data Science.
Дополнительно Dash легко разворачивается на Heroku, Render или любой другой платформе с поддержкой Python. А значит, ты можешь делать прототипы, MVP и небольшие демонстрационные проекты без громоздких фреймворков.
Совет от меня: начни с чего-то простого. Например, загрузка CSV-файла и построение графика по выбранным колонкам. Это поможет понять принципы связи layout-компонентов и callback-функций. А дальше — хоть предиктивная аналитика с машинным обучением!
Dash не заменит тебе полноценную веб-разработку, но если ты Python-разработчик, которому нужно быстро визуализировать данные — это просто находка.
❤1🔥1
🔍 Создание и настройка сред тестирования для Python проектов
Если вы только начинаете путешествие по миру Python, рано или поздно столкнётесь с необходимостью тестировать свой код. И вот тут начинается магия: автоматические тесты, виртуальные окружения, покрытие кода — всё это становится неотъемлемой частью любого серьёзного проекта. Сегодня разберём, как создать и настроить удобную и гибкую среду тестирования, с которой приятно работать.
🎯 Начнем с основ: виртуальное окружение
Работаем только в virtual environment. Это спасёт вас от конфликтов зависимостей и превращения системы в «зоопарк» библиотек.
Создаём окружение:
Теперь все зависимости будут установлены локально. Отлично!
🧪 Подключаем pytest
Для начала работы с тестами советую использовать
Создайте файл с тестами
Запуск всех тестов:
🔥 Бонус: автопоиск файлов с тестами, читаемые отчёты и подсветка ошибок прямо в терминале!
📦 Организация структуры проекта
Хорошая структура проекта помогает тестированию:
В
📈 Настройка покрытия кода
Хотите знать, сколько строк вашего кода реально покрыто тестами? Добавьте
Результат вас удивит: будет показано, какие строки были выполнены, а какие – нет. Это незаменимо для отслеживания «мертвого» кода.
🔧 Прогон тестов перед коммитом
Используйте pre-commit hooks, чтобы тесты автоматически запускались перед отправкой коммитов. Добавим файл
Устанавливаем и активируем:
Теперь каждая попытка зафиксировать изменения будет сопровождаться автоматической проверкой формата и, при желании, запуском тестов.
📚 Резюмируем
- Используйте
-
- Настройте
- Подключайте
- Используйте
Грамотно выстроенная среда тестирования экономит часы отладки, делает проект масштабируемым и увеличивает ваше доверие к собственному коду. Успехов! 🚀
Если вы только начинаете путешествие по миру Python, рано или поздно столкнётесь с необходимостью тестировать свой код. И вот тут начинается магия: автоматические тесты, виртуальные окружения, покрытие кода — всё это становится неотъемлемой частью любого серьёзного проекта. Сегодня разберём, как создать и настроить удобную и гибкую среду тестирования, с которой приятно работать.
🎯 Начнем с основ: виртуальное окружение
Работаем только в virtual environment. Это спасёт вас от конфликтов зависимостей и превращения системы в «зоопарк» библиотек.
Создаём окружение:
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
Теперь все зависимости будут установлены локально. Отлично!
🧪 Подключаем pytest
Для начала работы с тестами советую использовать
pytest
. Он лаконичен, мощен и популярен в сообществе. Установим его:pip install pytest
Создайте файл с тестами
test_math_utils.py
:def add(a, b):
return a + b
def test_add_positive_numbers():
assert add(2, 3) == 5
def test_add_negative_numbers():
assert add(-1, -1) == -2
Запуск всех тестов:
pytest
🔥 Бонус: автопоиск файлов с тестами, читаемые отчёты и подсветка ошибок прямо в терминале!
📦 Организация структуры проекта
Хорошая структура проекта помогает тестированию:
my_project/
│
├── src/
│ └── core.py
├── tests/
│ └── test_core.py
├── requirements.txt
└── pytest.ini
В
pytest.ini
можно настраивать поведение pytest
:[pytest]
testpaths = tests
python_files = test_*.py
📈 Настройка покрытия кода
Хотите знать, сколько строк вашего кода реально покрыто тестами? Добавьте
pytest-cov
:pip install pytest-cov
pytest --cov=src tests/
Результат вас удивит: будет показано, какие строки были выполнены, а какие – нет. Это незаменимо для отслеживания «мертвого» кода.
🔧 Прогон тестов перед коммитом
Используйте pre-commit hooks, чтобы тесты автоматически запускались перед отправкой коммитов. Добавим файл
.pre-commit-config.yaml
:repos:
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.3.2
hooks:
- id: prettier
- repo: https://github.com/pre-commit/mirrors-pylint
rev: v2.13.9
hooks:
- id: pylint
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.6.0
hooks:
- id: autopep8
Устанавливаем и активируем:
pip install pre-commit
pre-commit install
Теперь каждая попытка зафиксировать изменения будет сопровождаться автоматической проверкой формата и, при желании, запуском тестов.
📚 Резюмируем
- Используйте
venv
для изоляции сред-
pytest
– ваш друг в мире тестов- Настройте
pytest.ini
под структуру проекта- Подключайте
pytest-cov
для анализа покрытия- Используйте
pre-commit
для автоматизации проверокГрамотно выстроенная среда тестирования экономит часы отладки, делает проект масштабируемым и увеличивает ваше доверие к собственному коду. Успехов! 🚀
Название: Сценарий оживает — пишем интерактивные фильмы на Python
Интерактивное кино — это где пользователь чувствует себя режиссёром. Помните Black Mirror: Bandersnatch? Или игры от Telltale? Хочешь такого же эффекта, но на Python? Легко.
В этом посте я расскажу, как создавать интерактивные сценарии, с поддержкой переходов, ветвлений и даже "оцифровки" сюжета — структуру, по которой можно визуализировать сюжет как дерево.
Ключевая идея — представить сценарий в виде графа, где каждая сцена — это узел, а выбор — это ребро. Для начала создадим структуру сцены.
📦 Основной ингредиент: простая модель сцены
Каждая сцена включает текст и возможные выборы. Попробуем построить мини-историю.
Теперь сделаем функцию, которая будет прогонять пользователя через историю.
И запускаем:
📊 Теперь — оцифровка: дерево выбора
Допустим, ты хочешь отрисовать структуру сюжета. Здесь пригодится модуль graphviz.
Установим его:
Теперь можно визуализировать сюжет:
В результате получим PNG-диаграмму с графом всех сцен. Это удобно, когда сценарий становится большим и запутанным.
🧩 Идеи для расширения:
- Добавить условные переходы в зависимости от состояния игрока (что он уже выбрал ранее).
- Сохранять прохождения.
- Автоматическая генерация HTML/Web-интерфейса.
- Генерация сценария из JSON или YAML — удобно авторам без знаний Python.
🎬 Вывод
На Python легко создать интерактивную историю, точнее — движок для неё. Но самый главный ингредиент — твоя фантазия. Python в этом случае — режиссёрская панель и монтажный отсек одновременно. Такое кино ты нигде не купишь — ты его пишешь сам.
Интерактивное кино — это где пользователь чувствует себя режиссёром. Помните Black Mirror: Bandersnatch? Или игры от Telltale? Хочешь такого же эффекта, но на Python? Легко.
В этом посте я расскажу, как создавать интерактивные сценарии, с поддержкой переходов, ветвлений и даже "оцифровки" сюжета — структуру, по которой можно визуализировать сюжет как дерево.
Ключевая идея — представить сценарий в виде графа, где каждая сцена — это узел, а выбор — это ребро. Для начала создадим структуру сцены.
📦 Основной ингредиент: простая модель сцены
class Scene:
def __init__(self, text, choices):
self.text = text
self.choices = choices # {'choice_text': next_scene_key}
Каждая сцена включает текст и возможные выборы. Попробуем построить мини-историю.
story = {
"start": Scene(
"Ты просыпаешься в лесу. На севере слышны шаги. На юге видишь свет костра.",
{
"Пойти на север": "north_path",
"Пойти на юг": "campfire"
}
),
"north_path": Scene(
"Ты натыкаешься на странного мужчину с топором.",
{
"Поздороваться": "talk_man",
"Спрятаться": "hide"
}
),
"campfire": Scene(
"Около костра сидят путешественники. Они машут тебе рукой.",
{
"Присоединиться": "join_travelers",
"Убежать в лес": "run_away"
}
),
# ...
}
Теперь сделаем функцию, которая будет прогонять пользователя через историю.
def play(story, start_key):
current_key = start_key
while current_key in story:
scene = story[current_key]
print(f"\n{scene.text}\n")
for i, choice in enumerate(scene.choices.keys(), 1):
print(f"{i}. {choice}")
try:
index = int(input("Выбери действие: ")) - 1
choice_text = list(scene.choices.keys())[index]
current_key = scene.choices[choice_text]
except (IndexError, ValueError):
print("Неверный выбор. Попробуй снова.")
И запускаем:
if __name__ == "__main__":
play(story, "start")
📊 Теперь — оцифровка: дерево выбора
Допустим, ты хочешь отрисовать структуру сюжета. Здесь пригодится модуль graphviz.
Установим его:
pip install graphviz
Теперь можно визуализировать сюжет:
from graphviz import Digraph
def export_story_graph(story, filename="story"):
dot = Digraph()
for key, scene in story.items():
dot.node(key, scene.text[:30] + ("..." if len(scene.text) > 30 else ""))
for choice_text, next_key in scene.choices.items():
dot.edge(key, next_key, label=choice_text)
dot.render(filename, format='png', cleanup=True)
export_story_graph(story)
В результате получим PNG-диаграмму с графом всех сцен. Это удобно, когда сценарий становится большим и запутанным.
🧩 Идеи для расширения:
- Добавить условные переходы в зависимости от состояния игрока (что он уже выбрал ранее).
- Сохранять прохождения.
- Автоматическая генерация HTML/Web-интерфейса.
- Генерация сценария из JSON или YAML — удобно авторам без знаний Python.
🎬 Вывод
На Python легко создать интерактивную историю, точнее — движок для неё. Но самый главный ингредиент — твоя фантазия. Python в этом случае — режиссёрская панель и монтажный отсек одновременно. Такое кино ты нигде не купишь — ты его пишешь сам.
Python и Makefile: друзья или соседи, которые делают вид, что не знакомы? Большинство начинающих разработчиков вообще не знают, что у них под носом скрыт весьма могущественный инструмент автоматизации — Makefile. Если вы всё ещё вручную запускаете тесты, линтеры, форматтеры, и каждый раз вспоминаете, какой командой деплоится скрипт — пора знакомиться с make.
Makefile — это не пережиток C-прошлого. Его можно отлично использовать в проектах на Python, чтобы стандартизировать и автоматизировать повседневные задачи: запуск тестов, линтинг, форматирование кода, сбор документации, и многое другое. Плюс — он кросс-платформенный и не требует установки дополнительных зависимостей.
Давайте рассмотрим, как можно организовать простой Makefile под типичный проект на Python.
Предположим, у нас в проекте есть следующая структура:
Вот базовый вариант Makefile, который выполняет часто повторяющиеся задачи:
Что здесь происходит?
- install — установка зависимостей проекта.
- test — запуск ваших тестов, например, с помощью pytest.
- lint — проверка стиля кода с помощью flake8.
- format — автоматическое форматирование при помощи black.
- run — запуск основного скрипта проекта.
Допустим, вы хотите быстро проверить код перед коммитом. Одной командой вы можете прогнать форматтер, линтер и тесты:
А если проект сложнее? Например, у вас разные настройки для dev и prod окружений. Тогда Makefile спасает и здесь:
Или хотите максимально упростить работу в команде? Добавьте цель init:
Теперь новому участнику команды достаточно одной команды make init, и он получит всё необходимое для старта.
Особенность Makefile в его декларативности. Вы просто пишете, что хотите сделать, а make разруливает зависимости и порядок выполнения. Даже если вы профи в bash-скриптах, Makefile удобно читается и отлично документирует процессы.
В завершение — если вы думаете, что Makefile — это только для бэкенда или devops-разработчиков, вы удивитесь, как хорошо он встраивается даже в ML-проекты, автоматизируя запуск моделей, сбор данных, преобразования и т.д.
Автоматизация = скорость + надежность. С Makefile вы тратите меньше времени на рутину, и больше — на собственно код. А Python и Makefile — невероятно гармоничная пара, когда нужно наладить процесс, но не хочется городить сложные системы сборки.
Makefile — это не пережиток C-прошлого. Его можно отлично использовать в проектах на Python, чтобы стандартизировать и автоматизировать повседневные задачи: запуск тестов, линтинг, форматирование кода, сбор документации, и многое другое. Плюс — он кросс-платформенный и не требует установки дополнительных зависимостей.
Давайте рассмотрим, как можно организовать простой Makefile под типичный проект на Python.
Предположим, у нас в проекте есть следующая структура:
my_project/
├── src/
│ └── main.py
├── tests/
│ └── test_main.py
├── requirements.txt
├── Makefile
Вот базовый вариант Makefile, который выполняет часто повторяющиеся задачи:
.PHONY: install test lint format run
install:
pip install -r requirements.txt
test:
pytest tests/
lint:
flake8 src/ tests/
format:
black src/ tests/
run:
python src/main.py
Что здесь происходит?
- install — установка зависимостей проекта.
- test — запуск ваших тестов, например, с помощью pytest.
- lint — проверка стиля кода с помощью flake8.
- format — автоматическое форматирование при помощи black.
- run — запуск основного скрипта проекта.
Допустим, вы хотите быстро проверить код перед коммитом. Одной командой вы можете прогнать форматтер, линтер и тесты:
make format lint test
А если проект сложнее? Например, у вас разные настройки для dev и prod окружений. Тогда Makefile спасает и здесь:
run-dev:
ENV=development python src/main.py
run-prod:
ENV=production python src/main.py
Или хотите максимально упростить работу в команде? Добавьте цель init:
init: install format lint test
Теперь новому участнику команды достаточно одной команды make init, и он получит всё необходимое для старта.
Особенность Makefile в его декларативности. Вы просто пишете, что хотите сделать, а make разруливает зависимости и порядок выполнения. Даже если вы профи в bash-скриптах, Makefile удобно читается и отлично документирует процессы.
В завершение — если вы думаете, что Makefile — это только для бэкенда или devops-разработчиков, вы удивитесь, как хорошо он встраивается даже в ML-проекты, автоматизируя запуск моделей, сбор данных, преобразования и т.д.
Автоматизация = скорость + надежность. С Makefile вы тратите меньше времени на рутину, и больше — на собственно код. А Python и Makefile — невероятно гармоничная пара, когда нужно наладить процесс, но не хочется городить сложные системы сборки.
Проектирование высоконагруженных систем на базе Python: мифы и реальность
Когда речь заходит о высоконагруженных системах, Python обычно воспринимается с опаской. “Медленный”, “интерпретируемый”, “не подходит для продакшена” — и это лишь малая часть мифов. Но на деле — Python способен справляться с серьёзными нагрузками, если использовать его правильно. Давайте разберёмся, на что он действительно способен и какие инструменты пригодятся.
🐍 Лёгкие, но мощные: FastAPI и Uvicorn
Для создания высокопроизводительного backend-сервиса важно выбрать правильный веб-фреймворк. Flask — хорош, но для серьёзных задач лучше использовать FastAPI. Он построен на Starlette и использует типизацию, что упрощает отладку и повышает читаемость кода.
Пример минимального, но асинхронного API:
Запуск через Uvicorn:
Uvicorn — это ASGI-сервер, который обрабатывает запросы асинхронно и масштабируется за счёт запуска нескольких воркеров.
⚙️ Асинхронность = масштабируемость
Python не любит многопоточность из-за GIL (Global Interpreter Lock), но с асинхронным кодом справляется отлично. Используйте
Пример с aiohttp:
🧵 Background-задачи и воркеры: Celery, RQ
Если ваш сервис выполняет тяжёлые задачи (например, генерация отчёта или отправка email), лучше выносить их из основного потока. Для этого используют Celery или RQ. Эти библиотеки работают с очередями (Redis, RabbitMQ) и позволяют обрабатывать задачи в фоне.
Пример задачи на Celery:
Основной сервис отдаёт задачу в очередь, рабочие процессы Celery её исполняют — и ваш API не блокируется.
📦 Кэш как спасение: Redis и Memcached
Часто повторяющиеся вычисления можно кэшировать. Например, если запрос к БД занимает 300 мс, а вы получаете одинаковые данные каждую минуту — кэш устранит задержку. Варианты:
- Redis (популярный, кроссплатформенный, даёт TTL, pub/sub и даже persistent-режим)
- Memcached (чуть быстрее по памяти, но без поддержки сложных типов данных)
Пример с redis-py:
🧠 Мониторинг и профилирование
Знать узкие места в коде — половина успеха.
Когда речь заходит о высоконагруженных системах, Python обычно воспринимается с опаской. “Медленный”, “интерпретируемый”, “не подходит для продакшена” — и это лишь малая часть мифов. Но на деле — Python способен справляться с серьёзными нагрузками, если использовать его правильно. Давайте разберёмся, на что он действительно способен и какие инструменты пригодятся.
🐍 Лёгкие, но мощные: FastAPI и Uvicorn
Для создания высокопроизводительного backend-сервиса важно выбрать правильный веб-фреймворк. Flask — хорош, но для серьёзных задач лучше использовать FastAPI. Он построен на Starlette и использует типизацию, что упрощает отладку и повышает читаемость кода.
Пример минимального, но асинхронного API:
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping")
async def ping():
return {"message": "pong"}
Запуск через Uvicorn:
uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4
Uvicorn — это ASGI-сервер, который обрабатывает запросы асинхронно и масштабируется за счёт запуска нескольких воркеров.
⚙️ Асинхронность = масштабируемость
Python не любит многопоточность из-за GIL (Global Interpreter Lock), но с асинхронным кодом справляется отлично. Используйте
asyncio
, чтобы обрабатывать тысячи соединений одновременно, например, когда пишите WebSocket-сервер или микросервис, который часто обращается к внешним API.Пример с aiohttp:
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://example.com')
print(html)
asyncio.run(main())
🧵 Background-задачи и воркеры: Celery, RQ
Если ваш сервис выполняет тяжёлые задачи (например, генерация отчёта или отправка email), лучше выносить их из основного потока. Для этого используют Celery или RQ. Эти библиотеки работают с очередями (Redis, RabbitMQ) и позволяют обрабатывать задачи в фоне.
Пример задачи на Celery:
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def add(a, b):
return a + b
Основной сервис отдаёт задачу в очередь, рабочие процессы Celery её исполняют — и ваш API не блокируется.
📦 Кэш как спасение: Redis и Memcached
Часто повторяющиеся вычисления можно кэшировать. Например, если запрос к БД занимает 300 мс, а вы получаете одинаковые данные каждую минуту — кэш устранит задержку. Варианты:
- Redis (популярный, кроссплатформенный, даёт TTL, pub/sub и даже persistent-режим)
- Memcached (чуть быстрее по памяти, но без поддержки сложных типов данных)
Пример с redis-py:
import redis
cache = redis.Redis(host='localhost', port=6379, db=0)
def get_data():
cached = cache.get("key")
if cached:
return cached
# expensive operation
result = "expensive_result"
cache.setex("key", 60, result)
return result
🧠 Мониторинг и профилирование
Знать узкие места в коде — половина успеха.
Используйте:
-
-
- Grafana + Prometheus для визуализации
- Sentry для отслеживания ошибок и задержек
Пример сбора метрик:
🌐 Масштабирование и развертывание
Когда одна машина уже не тянет, разделяйте:
- API и воркеры — разные контейнеры
- Чтение/запись в БД — через реплики
- Сервис — в k8s или Docker Swarm
- Балансировка — Nginx, HAProxy
Python отлично вписывается в микросервисную инфраструктуру.
💡 Вывод
Python не предназначен быть “голым железом”, как C++, но в грамотных руках — это отличный инструмент для высоконагруженных API, фоновых систем и даже realtime-сервисов. Используйте асинхронность, кэш, очереди, мониторинг — и Python не подведёт.
-
cProfile
для анализа производительности-
prometheus_client
для метрик- Grafana + Prometheus для визуализации
- Sentry для отслеживания ошибок и задержек
Пример сбора метрик:
from prometheus_client import start_http_server, Summary
import time
import random
REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request')
@REQUEST_TIME.time()
def process_request():
time.sleep(random.random())
if __name__ == '__main__':
start_http_server(8001)
while True:
process_request()
🌐 Масштабирование и развертывание
Когда одна машина уже не тянет, разделяйте:
- API и воркеры — разные контейнеры
- Чтение/запись в БД — через реплики
- Сервис — в k8s или Docker Swarm
- Балансировка — Nginx, HAProxy
Python отлично вписывается в микросервисную инфраструктуру.
💡 Вывод
Python не предназначен быть “голым железом”, как C++, но в грамотных руках — это отличный инструмент для высоконагруженных API, фоновых систем и даже realtime-сервисов. Используйте асинхронность, кэш, очереди, мониторинг — и Python не подведёт.
🎮 Python-геймдев и античиты: магия PyMunk под капотом
Вы когда-нибудь задумывались, как в двухмерных играх работают физика и защита от несанкционированного вмешательства? Большинство новичков, погружающихся в разработку игр на Python, в какой-то момент сталкиваются с тем, что их проект слишком легко "взламывается". Давайте разберёмся, как использовать библиотеку PyMunk не только для реалистичной физики, но и в качестве инструмента для защиты вашего игрового мира от читеров.
🛠 Что такое PyMunk
PyMunk — это высокоуровневая обертка над физическим движком Chipmunk2D. Он позволяет просто и понятно внедрять физику в 2D-игры. Но что важнее — PyMunk сам управляет логикой движения объектов, силами и столкновениями. Это значит, что любые попытки напрямую “подкрутить” данные через память или простую модификацию кода станут неэффективны.
🚫 Почему читеры обходят обычную физику
Когда вы пишете игру на Python "на коленке", например:
Злоумышленнику достаточно изменить значение
🧠 PyMunk как физическая истина
Рассмотрим пример, где персонаж управляется через силы, а не напрямую координатами.
Здесь управление персонажем идёт через applyforceatlocalpoint. Координаты тела нельзя "просто так" изменить — сила и масса диктуют движение. Модифицировать
🛡 Античит как побочный бонус
Эта архитектура имеет важное преимущество: вы отделяете “визуал” от “реальности”. Даже если кто-то перехватывает ввод или пытается симулировать нажатие клавиш, он не может точно контролировать координаты игрока. А если добавить проверку состояния тел (например, не прыгнул ли игрок без касания земли), можно отловить и навесить флаг “подозрительного поведения”.
Кроме того, движения можно валидировать сервером (если игра сетевого типа) именно на уровне физических параметров: сила, ускорение, импульс. Сравнить два вектора легче, чем разбираться, почему игрок внезапно оказался в стене.
🔒 Финальные советы
- Никогда не давайте игроку прямого доступа к координатам тел.
- Используйте физику, а не “магические” перемещения.
- Логируйте входящие силы и действия — на редкость полезно в отладке и аналитике.
- PyMunk отлично сочетается с серверной проверкой, если решите двигаться к многопользовательским играм.
Итог: PyMunk — это не просто реалистичные прыжки и катящиеся шарики. Это база для создания устойчивой системы геймплея, где поведение игроков подчиняется законам физики, а не желаниям хакера. Если ищете способ сделать игру устойчивее к взлому — используйте физику как истину.
Вы когда-нибудь задумывались, как в двухмерных играх работают физика и защита от несанкционированного вмешательства? Большинство новичков, погружающихся в разработку игр на Python, в какой-то момент сталкиваются с тем, что их проект слишком легко "взламывается". Давайте разберёмся, как использовать библиотеку PyMunk не только для реалистичной физики, но и в качестве инструмента для защиты вашего игрового мира от читеров.
🛠 Что такое PyMunk
PyMunk — это высокоуровневая обертка над физическим движком Chipmunk2D. Он позволяет просто и понятно внедрять физику в 2D-игры. Но что важнее — PyMunk сам управляет логикой движения объектов, силами и столкновениями. Это значит, что любые попытки напрямую “подкрутить” данные через память или простую модификацию кода станут неэффективны.
🚫 Почему читеры обходят обычную физику
Когда вы пишете игру на Python "на коленке", например:
player.x += 5
Злоумышленнику достаточно изменить значение
player.x
в отладчике, и его персонаж «телепортируется». Однако если движение объекта вычисляется исключительно в физическом мире движка, вмешательство становится затруднительным.🧠 PyMunk как физическая истина
Рассмотрим пример, где персонаж управляется через силы, а не напрямую координатами.
import pymunk
import pymunk.pygame_util
import pygame
pygame.init()
screen = pygame.display.set_mode((600, 400))
clock = pygame.time.Clock()
space = pymunk.Space()
space.gravity = (0, 900)
def create_player(space):
body = pymunk.Body(1, pymunk.moment_for_circle(1, 0, 25))
body.position = 100, 100
shape = pymunk.Circle(body, 25)
shape.elasticity = 0.5
space.add(body, shape)
return body
player_body = create_player(space)
draw_options = pymunk.pygame_util.DrawOptions(screen)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_body.apply_force_at_local_point((-1500, 0), (0, 0))
if keys[pygame.K_RIGHT]:
player_body.apply_force_at_local_point((1500, 0), (0, 0))
screen.fill((255, 255, 255))
space.step(1/60)
space.debug_draw(draw_options)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Здесь управление персонажем идёт через applyforceatlocalpoint. Координаты тела нельзя "просто так" изменить — сила и масса диктуют движение. Модифицировать
player_body.position
вручную — бесполезно: на следующем кадре PyMunk всё пересчитает обратно по физике.🛡 Античит как побочный бонус
Эта архитектура имеет важное преимущество: вы отделяете “визуал” от “реальности”. Даже если кто-то перехватывает ввод или пытается симулировать нажатие клавиш, он не может точно контролировать координаты игрока. А если добавить проверку состояния тел (например, не прыгнул ли игрок без касания земли), можно отловить и навесить флаг “подозрительного поведения”.
Кроме того, движения можно валидировать сервером (если игра сетевого типа) именно на уровне физических параметров: сила, ускорение, импульс. Сравнить два вектора легче, чем разбираться, почему игрок внезапно оказался в стене.
🔒 Финальные советы
- Никогда не давайте игроку прямого доступа к координатам тел.
- Используйте физику, а не “магические” перемещения.
- Логируйте входящие силы и действия — на редкость полезно в отладке и аналитике.
- PyMunk отлично сочетается с серверной проверкой, если решите двигаться к многопользовательским играм.
Итог: PyMunk — это не просто реалистичные прыжки и катящиеся шарики. Это база для создания устойчивой системы геймплея, где поведение игроков подчиняется законам физики, а не желаниям хакера. Если ищете способ сделать игру устойчивее к взлому — используйте физику как истину.
🔄 Обработка потоков данных с Python и Apache Storm: первая встреча
Всем привет! Сегодня поговорим о чем-то по-настоящему живом — потоковых данных. Представьте Twitter-ленту, клики пользователей на сайте или датчики в IoT — всё это нескончаемые потоки событий. Для их реального времени обработки часто используют Apache Storm. Он мощный, масштабируемый и работает под лозунгом: “боевой зубастый молниеносный фермер потоков”.
Но у Storm есть коварная особенность — родной язык для написания логики обработки данных в нём это Java. К счастью, есть библиотека streamparse — она позволяет писать topologies на Python и запускать их в Apache Storm. Сегодня покажу, как это работает.
📦 Установка
Для начала убедитесь, что у вас установлен Apache Storm (версии 1.x). Далее установим streamparse:
Создаём проект:
Внутри проекта — готовая структура: папки для Spout и Bolt’ов, настройки, зависимости.
🌪 Что такое Spout и Bolt?
Spout — источник данных. Получает события "снаружи": из файла, очереди или API.
Bolt — обрабатывает данные. Например, парсит JSON, считает статистику, отправляет в БД.
⚡ Пример: считаем слова в потоке
Создадим Spout, который выдаёт предложения:
Теперь Bolt, который разбивает предложения на слова:
И ещё один Bolt, который считает слова:
🛠 Запускаем локально
Добавим в файл
Теперь можно запустить локально:
Вы увидите, как Apache Storm обрабатывает поток: предложения → слова → счётчики.
🎯 Зачем это нужно?
Apache Storm — не просто блажь ради распределённости. Он умеет:
- обрабатывать миллионы событий в секунду;
- масштабироваться по серверам;
- обеспечивать отказоустойчивость.
А с помощью streamparse вы сохраняете привычный Python, не углубляясь в джунгли Java.
📌 Вывод
Apache Storm и streamparse позволяют собирать мощные системы потоковой обработки на Python. Это отличный шаг, если вы работаете с реальным временем: логи, метрики, события. Да, он требует установки Java и самого Storm, но в обмен вы получаете надёжный и быстрый фреймворк.
Следующий раз разберём, как подключать Kafka и обрабатывать поток реальных сообщений. А пока — пусть молнии потекут по Python-контактам! ⚡🐍
— Иван.
Всем привет! Сегодня поговорим о чем-то по-настоящему живом — потоковых данных. Представьте Twitter-ленту, клики пользователей на сайте или датчики в IoT — всё это нескончаемые потоки событий. Для их реального времени обработки часто используют Apache Storm. Он мощный, масштабируемый и работает под лозунгом: “боевой зубастый молниеносный фермер потоков”.
Но у Storm есть коварная особенность — родной язык для написания логики обработки данных в нём это Java. К счастью, есть библиотека streamparse — она позволяет писать topologies на Python и запускать их в Apache Storm. Сегодня покажу, как это работает.
📦 Установка
Для начала убедитесь, что у вас установлен Apache Storm (версии 1.x). Далее установим streamparse:
pip install streamparse
Создаём проект:
sparse quickstart storm_example
cd storm_example
Внутри проекта — готовая структура: папки для Spout и Bolt’ов, настройки, зависимости.
🌪 Что такое Spout и Bolt?
Spout — источник данных. Получает события "снаружи": из файла, очереди или API.
Bolt — обрабатывает данные. Например, парсит JSON, считает статистику, отправляет в БД.
⚡ Пример: считаем слова в потоке
Создадим Spout, который выдаёт предложения:
from streamparse import Spout
import random
class SentenceSpout(Spout):
def initialize(self, stormconf, context):
self.sentences = ["hello world", "python storm integration", "stream processing rocks"]
def next_tuple(self):
sentence = random.choice(self.sentences)
self.emit([sentence])
Теперь Bolt, который разбивает предложения на слова:
from streamparse import Bolt
class SplitSentenceBolt(Bolt):
def process(self, tup):
sentence = tup.values[0]
for word in sentence.split():
self.emit([word])
И ещё один Bolt, который считает слова:
from streamparse import Bolt
from collections import defaultdict
class WordCountBolt(Bolt):
def initialize(self, conf, ctx):
self.counts = defaultdict(int)
def process(self, tup):
word = tup.values[0]
self.counts[word] += 1
self.log(f"{word}: {self.counts[word]}")
🛠 Запускаем локально
Добавим в файл
topologies/wordcount.py
описание топологии:from streamparse import Grouping, Topology
from bolts.word_count import WordCountBolt
from bolts.split_sentence import SplitSentenceBolt
from spouts.sentence import SentenceSpout
class WordCountTopology(Topology):
sentence_spout = SentenceSpout.spec()
splitter_bolt = SplitSentenceBolt.spec(inputs=[sentence_spout])
counter_bolt = WordCountBolt.spec(inputs=[splitter_bolt], par=2)
Теперь можно запустить локально:
sparse run
Вы увидите, как Apache Storm обрабатывает поток: предложения → слова → счётчики.
🎯 Зачем это нужно?
Apache Storm — не просто блажь ради распределённости. Он умеет:
- обрабатывать миллионы событий в секунду;
- масштабироваться по серверам;
- обеспечивать отказоустойчивость.
А с помощью streamparse вы сохраняете привычный Python, не углубляясь в джунгли Java.
📌 Вывод
Apache Storm и streamparse позволяют собирать мощные системы потоковой обработки на Python. Это отличный шаг, если вы работаете с реальным временем: логи, метрики, события. Да, он требует установки Java и самого Storm, но в обмен вы получаете надёжный и быстрый фреймворк.
Следующий раз разберём, как подключать Kafka и обрабатывать поток реальных сообщений. А пока — пусть молнии потекут по Python-контактам! ⚡🐍
— Иван.