Создание базового TCP‑сервера с использованием сокетов Python
Иногда хочется почувствовать себя чуть ближе к «низам» интернета — туда, где нет Flask и Django, а есть только чистые сокеты и байты. Давайте напишем свой минимальный TCP‑сервер и разберёмся, что вообще происходит «под капотом».
### Что такое сокет?
Сокет — это конечная точка сетевого соединения. У простого TCP-сервера есть три основных шага:
1. Создать сокет.
2. Привязать его к адресу и порту.
3. Слушать входящие подключения и обрабатывать клиентов.
Используем стандартный модуль
### Самый простой TCP‑сервер
Напишем сервер, который принимает соединение и отсылает клиенту приветствие:
Кратко по шагам:
-
-
-
-
-
Проверить можно через
### Эхо‑сервер: отвечаем на сообщения
Сделаем сервер, который читает данные от клиента и отправляет их обратно:
Здесь важно:
-
-
- цикл
### О чём стоит помнить
- Порт должен быть свободен, иначе будет ошибка
- При разработке удобно использовать
- Такой сервер однопоточен: пока он общается с одним клиентом, другие ждут. Для реальных задач нужны потоки (
Через такие простые примеры становится понятнее, что веб‑фреймворки всего лишь надстройка над таким же
Иногда хочется почувствовать себя чуть ближе к «низам» интернета — туда, где нет Flask и Django, а есть только чистые сокеты и байты. Давайте напишем свой минимальный TCP‑сервер и разберёмся, что вообще происходит «под капотом».
### Что такое сокет?
Сокет — это конечная точка сетевого соединения. У простого TCP-сервера есть три основных шага:
1. Создать сокет.
2. Привязать его к адресу и порту.
3. Слушать входящие подключения и обрабатывать клиентов.
Используем стандартный модуль
socket.### Самый простой TCP‑сервер
Напишем сервер, который принимает соединение и отсылает клиенту приветствие:
import socket
HOST = "127.0.0.1" # localhost
PORT = 5000 # любой свободный порт > 1024
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(1) # максимальная очередь из 1 клиента
print(f"Server is listening on {HOST}:{PORT}...")
conn, addr = server_socket.accept()
print(f"Connected by {addr}")
message = "Hello from TCP server!\n"
conn.sendall(message.encode("utf-8"))
conn.close()
server_socket.close()
Кратко по шагам:
-
socket.AF_INET — IPv4;-
socket.SOCK_STREAM — протокол TCP;-
bind — говорим ОС: «Этот сервер живёт на HOST:PORT»;-
listen — включаем режим ожидания подключений;-
accept — блокируется, пока клиент не подключится, и возвращает новый сокет conn только для этого клиента.Проверить можно через
telnet 127.0.0.1 5000 или написать маленького клиента.### Эхо‑сервер: отвечаем на сообщения
Сделаем сервер, который читает данные от клиента и отправляет их обратно:
import socket
HOST = "127.0.0.1"
PORT = 5001
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
print(f"Echo server on {HOST}:{PORT}")
while True:
conn, addr = server_socket.accept()
print(f"Client connected: {addr}")
with conn:
while True:
data = conn.recv(1024) # читаем до 1024 байт
if not data:
break # клиент закрыл соединение
print(f"Received: {data!r}")
conn.sendall(data) # отправляем назад
Здесь важно:
-
recv возвращает bytes; пустые b"" означают разрыв соединения;-
sendall гарантирует отправку всего буфера;- цикл
while True позволяет обслуживать клиентов один за другим.### О чём стоит помнить
- Порт должен быть свободен, иначе будет ошибка
OSError: [Errno 98] Address already in use.- При разработке удобно использовать
127.0.0.1, для внешнего доступа — "0.0.0.0".- Такой сервер однопоточен: пока он общается с одним клиентом, другие ждут. Для реальных задач нужны потоки (
threading) или asyncio.Через такие простые примеры становится понятнее, что веб‑фреймворки всего лишь надстройка над таким же
socket, который вы сейчас написали сами.👍3
Как настроить GitHub Actions для Python-проекта: CI за 10 минут
Ты пишешь код, пушишь его в репозиторий… и только потом вспоминаешь, что не запустил тесты. Классика. GitHub Actions решает эту проблему: он запускает проверки автоматически при каждом коммите или pull request.
Разберём минимальный, но полезный воркфлоу для Python.
---
### Шаг 1. Структура проекта
Допустим, у тебя такой проект:
---
### Шаг 2. Пишем простой код и тест
Добавь
---
### Шаг 3. Создаём воркфлоу GitHub Actions
В репозитории создай папку
Что тут происходит:
-
-
-
-
-
-
---
### Шаг 4. Бонус: проверка стиля
Добавим линтер
И ещё один шаг в воркфлоу:
Теперь каждый коммит проходит:
1. Установку зависимостей
2. Линтер
3. Тесты на нескольких версиях Python
Если что-то падает — GitHub подсветит это прямо в Pull Request.
---
GitHub Actions превращает твой репозиторий в маленький конвейер качества: ты пишешь код — он сам проверяет, что ты ничего не сломал. Настроить один раз — экономить часы и нервы постоянно.
Ты пишешь код, пушишь его в репозиторий… и только потом вспоминаешь, что не запустил тесты. Классика. GitHub Actions решает эту проблему: он запускает проверки автоматически при каждом коммите или pull request.
Разберём минимальный, но полезный воркфлоу для Python.
---
### Шаг 1. Структура проекта
Допустим, у тебя такой проект:
.
├─ src/
│ └─ main.py
├─ tests/
│ └─ test_main.py
├─ requirements.txt
└─ pyproject.toml (или setup.cfg / setup.py — не критично)
tests/ — место для тестов, requirements.txt — зависимости.---
### Шаг 2. Пишем простой код и тест
src/main.py:def add(a: int, b: int) -> int:
return a + b
tests/test_main.py:from src.main import add
def test_add_positive():
assert add(2, 3) == 5
def test_add_negative():
assert add(-1, -3) == -4
Добавь
pytest в requirements.txt:pytest==8.3.0
---
### Шаг 3. Создаём воркфлоу GitHub Actions
В репозитории создай папку
.github/workflows/ и файл, например python-ci.yml.name: Python CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest -q
Что тут происходит:
-
on — когда запускать воркфлоу: при push и pull_request в main.-
matrix — прогоняем тесты на нескольких версиях Python.-
actions/checkout — забирает код из репозитория.-
actions/setup-python — ставит нужную версию Python.-
Install dependencies — ставим зависимости.-
Run tests — запускаем pytest.---
### Шаг 4. Бонус: проверка стиля
Добавим линтер
flake8:requirements.txt:pytest==8.3.0
flake8==7.1.0
И ещё один шаг в воркфлоу:
- name: Lint with flake8
run: |
flake8 src tests
Теперь каждый коммит проходит:
1. Установку зависимостей
2. Линтер
3. Тесты на нескольких версиях Python
Если что-то падает — GitHub подсветит это прямо в Pull Request.
---
GitHub Actions превращает твой репозиторий в маленький конвейер качества: ты пишешь код — он сам проверяет, что ты ничего не сломал. Настроить один раз — экономить часы и нервы постоянно.
👍2
Введение в matplotlib: базовые графики и стильные фишки
Matplotlib — это как карандаш для программиста: без него работать можно, но рисовать данные неудобно. Библиотека умеет строить почти любые графики, а начинать лучше с простого: линейных, точечных и столбчатых диаграмм.
---
### Первый график за 5 строк
Установите библиотеку (если нужно):
Базовый пример:
---
### Цвета, маркеры и стили линий
Matplotlib позволяет легко “приодеть” график:
Что полезно запомнить:
-
-
-
-
---
### Точечные и столбчатые графики
Для разброса точек используйте
Параметры:
Столбчатая диаграмма:
---
### Быстрая смена стиля оформления
Matplotlib поддерживает готовые стили:
Один вызов
---
Matplotlib хорош тем, что простой код уже даёт читабельные графики, а добавляя по одному параметру — цвет, легенду, стиль — вы постепенно превращаете “сырой” график в понятную визуализацию.
Matplotlib — это как карандаш для программиста: без него работать можно, но рисовать данные неудобно. Библиотека умеет строить почти любые графики, а начинать лучше с простого: линейных, точечных и столбчатых диаграмм.
---
### Первый график за 5 строк
Установите библиотеку (если нужно):
pip install matplotlib
Базовый пример:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [2, 3, 5, 7]
plt.plot(x, y)
plt.title("Simple line plot")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.show()
plot — линия, title — заголовок, xlabel/ylabel — подписи осей, show — вывод окна с графиком.---
### Цвета, маркеры и стили линий
Matplotlib позволяет легко “приодеть” график:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y1 = [1, 4, 9, 16]
y2 = [2, 3, 2, 3]
plt.plot(x, y1, color="red", linestyle="--", marker="o", label="squares")
plt.plot(x, y2, color="#008080", linestyle="-.", marker="s", label="wavy")
plt.title("Styled lines")
plt.xlabel("X")
plt.ylabel("Y")
plt.legend()
plt.grid(True)
plt.show()
Что полезно запомнить:
-
color: "red", "green", "black" или HEX "#008080".-
linestyle: "-", "--", "-.", ":".-
marker: "o", "s", "x", "^" и др.-
legend() — показывает легенду по label.---
### Точечные и столбчатые графики
Для разброса точек используйте
scatter:import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [5, 3, 4, 2, 1]
plt.scatter(x, y, color="purple", s=80, alpha=0.7)
plt.title("Scatter plot")
plt.xlabel("X")
plt.ylabel("Y")
plt.grid(True)
plt.show()
Параметры:
s — размер точек, alpha — прозрачность.Столбчатая диаграмма:
import matplotlib.pyplot as plt
labels = ["Mon", "Tue", "Wed", "Thu", "Fri"]
values = [10, 12, 9, 15, 11]
plt.bar(labels, values, color="orange")
plt.title("Weekly stats")
plt.ylabel("Value")
plt.show()
---
### Быстрая смена стиля оформления
Matplotlib поддерживает готовые стили:
import matplotlib.pyplot as plt
plt.style.use("ggplot") # попробуйте также "seaborn-v0_8", "dark_background"
x = [1, 2, 3, 4]
y = [3, 8, 1, 10]
plt.plot(x, y, marker="o")
plt.title("Styled with ggplot")
plt.show()
Один вызов
plt.style.use — и у вас другой фон, сетка и палитра.---
Matplotlib хорош тем, что простой код уже даёт читабельные графики, а добавляя по одному параметру — цвет, легенду, стиль — вы постепенно превращаете “сырой” график в понятную визуализацию.
👍3
Как подружиться с
Почти каждый полезный скрипт рано или поздно превращается в маленькую консольную утилиту: нужно передать путь к файлу, режим работы, уровень логирования. Пихать всё в
---
### Базовый пример: обязательный аргумент
Скрипт, который приветствует пользователя по имени:
Запускаем из терминала:
Попробуйте
---
### Опциональные флаги и значения по умолчанию
Добавим флаг
Примеры запуска:
---
### Выбор из ограниченного набора значений
Частая задача — режим работы:
Если передать неправильное значение,
---
### Что в итоге
- разбирать позиционные и опциональные аргументы;
- автоматически генерировать
- проверять типы (
- ограничивать значения (
- удобно работать с флагами (
Освоив этот модуль, вы переводите свои скрипты из категории «сделал для себя» в категорию «это можно отдавать другим и не стыдиться».
argparse и сделать свой первый CLI-инструментПочти каждый полезный скрипт рано или поздно превращается в маленькую консольную утилиту: нужно передать путь к файлу, режим работы, уровень логирования. Пихать всё в
input() — путь страданий. Для этого в стандартной библиотеке есть модуль argparse, который превращает ваш скрипт в удобный CLI-инструмент с автогенерируемой справкой.---
### Базовый пример: обязательный аргумент
Скрипт, который приветствует пользователя по имени:
import argparse
parser = argparse.ArgumentParser(description="Simple greeting script")
parser.add_argument("name", help="User name to greet")
args = parser.parse_args()
print(f"Hello, {args.name}!")
Запускаем из терминала:
python greet.py Alice
# Hello, Alice!
Попробуйте
python greet.py -h — справка генерируется автоматически.---
### Опциональные флаги и значения по умолчанию
Добавим флаг
--uppercase и параметр --times:import argparse
parser = argparse.ArgumentParser(description="Advanced greeting script")
parser.add_argument("name", help="User name to greet")
parser.add_argument(
"-t", "--times",
type=int,
default=1,
help="How many times to repeat greeting"
)
parser.add_argument(
"-u", "--uppercase",
action="store_true",
help="Print greeting in uppercase"
)
args = parser.parse_args()
greeting = f"Hello, {args.name}!"
if args.uppercase:
greeting = greeting.upper()
for _ in range(args.times):
print(greeting)
Примеры запуска:
python greet.py Bob -t 3
python greet.py Bob -t 2 -u
---
### Выбор из ограниченного набора значений
Частая задача — режим работы:
debug, info, error. Используем choices:import argparse
parser = argparse.ArgumentParser(description="Logging level demo")
parser.add_argument(
"--level",
choices=["debug", "info", "error"],
default="info",
help="Logging level"
)
args = parser.parse_args()
print(f"Selected level: {args.level}")
Если передать неправильное значение,
argparse сам ругнется и покажет помощь.---
### Что в итоге
argparse умеет:- разбирать позиционные и опциональные аргументы;
- автоматически генерировать
-h/--help;- проверять типы (
type=int, float, и т.д.);- ограничивать значения (
choices);- удобно работать с флагами (
action="store_true").Освоив этот модуль, вы переводите свои скрипты из категории «сделал для себя» в категорию «это можно отдавать другим и не стыдиться».
👍1
Python для начинающих: автоматизируем Google Sheets через API
Работа с Excel надоела, а таблицы в Google Sheets растут как грибы? Самое время подключить Python и заставить таблицы работать за вас.
### Что понадобится
1. Аккаунт Google.
2. Включить Google Sheets API и создать Service Account в Google Cloud Console.
3. Скачать JSON‑ключ сервисного аккаунта.
4. Выдать этому сервисному аккаунту доступ к нужной таблице (Share → по email из JSON).
Устанавливаем нужные пакеты:
### Подключение к таблице
Теперь
### Чтение данных
Получим все строки и заголовок:
Так удобно превращать таблицу в «мини-базу данных».
### Запись и обновление
Запишем заголовок и пару строк:
Обновим цену в конкретной ячейке:
### Массовые обновления
Если нужно поменять сразу блок данных — используем диапазон:
### Небольшая автоматизация: перерасчёт итогов
Добавим в таблицу столбец с итоговой суммой:
Теперь таблица сама считает сумму по строке, а вы можете раз в день запускать скрипт и обновлять отчеты.
Google Sheets API + Python — это быстрый способ превратить обычную таблицу в часть автоматизированного пайплайна: собирать данные, очищать, пересчитывать и готовить отчеты без ручного копипаста.
Работа с Excel надоела, а таблицы в Google Sheets растут как грибы? Самое время подключить Python и заставить таблицы работать за вас.
### Что понадобится
1. Аккаунт Google.
2. Включить Google Sheets API и создать Service Account в Google Cloud Console.
3. Скачать JSON‑ключ сервисного аккаунта.
4. Выдать этому сервисному аккаунту доступ к нужной таблице (Share → по email из JSON).
Устанавливаем нужные пакеты:
pip install gspread google-auth
### Подключение к таблице
import gspread
from google.oauth2.service_account import Credentials
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
creds = Credentials.from_service_account_file(
"service_account.json",
scopes=SCOPES
)
client = gspread.authorize(creds)
sheet = client.open("Sales Report").sheet1 # первая вкладка
Теперь
sheet — это объект рабочей таблицы, с которым можно делать почти всё.### Чтение данных
Получим все строки и заголовок:
rows = sheet.get_all_records() # список dict'ов
header = sheet.row_values(1) # первая строка
print(header)
print(rows[:3]) # первые три записи
Так удобно превращать таблицу в «мини-базу данных».
### Запись и обновление
Запишем заголовок и пару строк:
data_header = ["Date", "Product", "Quantity", "Price"]
sheet.update("A1:D1", [data_header])
new_rows = [
["2025-01-01", "Keyboard", 3, 59.9],
["2025-01-02", "Mouse", 5, 29.5],
]
sheet.append_rows(new_rows)
append_rows добавляет данные в конец, не нужно считать, какая строка следующая.Обновим цену в конкретной ячейке:
sheet.update("D2", 79.9)
### Массовые обновления
Если нужно поменять сразу блок данных — используем диапазон:
discounted = [
["Keyboard", 49.9],
["Mouse", 24.9],
]
sheet.update("B2:C3", discounted)
### Небольшая автоматизация: перерасчёт итогов
Добавим в таблицу столбец с итоговой суммой:
values = sheet.get_all_values()
header = values[0]
rows = values[1:]
quantity_idx = header.index("Quantity")
price_idx = header.index("Price")
totals = []
for row in rows:
try:
qty = float(row[quantity_idx])
price = float(row[price_idx])
totals.append([qty * price])
except ValueError:
totals.append([""])
start_row = 2
end_row = start_row + len(totals) - 1
sheet.update(f"E{start_row}:E{end_row}", totals)
sheet.update("E1", "Total")
Теперь таблица сама считает сумму по строке, а вы можете раз в день запускать скрипт и обновлять отчеты.
Google Sheets API + Python — это быстрый способ превратить обычную таблицу в часть автоматизированного пайплайна: собирать данные, очищать, пересчитывать и готовить отчеты без ручного копипаста.
🔥3❤1
Как работать с параллельными потоками данных с Apache Kafka и Python
Представь себе конвейер в заводском цеху: по ленте бесконечно едут детали, а рабочие на разных станциях что‑то с ними делают. Apache Kafka — это примерно такой же конвейер, только для данных. Она позволяет принимать, хранить и отдавать миллионы сообщений в реальном времени. Python здесь может быть “рабочим”, который эти данные обрабатывает.
---
### Основные термины Kafka
- Broker — сервер Kafka, который хранит сообщения.
- Topic — “лента”, куда пишутся сообщения (например,
- Partition — кусок топика. Именно разделы позволяют обрабатывать сообщения параллельно.
- Producer — отправляет сообщения в Kafka.
- Consumer — читает сообщения из Kafka.
- Consumer group — группа потребителей, которые совместно читают один топик, автоматически деля партиции между собой.
Чем больше партиций у топика и чем больше потребителей в группе, тем выше параллелизм.
---
### Установка клиента для Python
Один из популярных клиентов —
---
### Простой producer: отправляем события
Сообщения попадают в топик
---
### Параллельное чтение: несколько consumers в одной группе
Ключ к параллельности — использовать одну consumer group и задать топику несколько партиций (например,
Теперь магия:
- Увеличиваешь количество процессов/контейнеров с этим consumer’ом — обработка масштабируется.
- Kafka сама следит, кто какие партиции читает, и перераспределяет их при падении одного из экземпляров.
---
### Практические советы
1. Думай о ключах сообщений: одинаковый ключ → одинаковая партиция → удобно гарантировать порядок для конкретного пользователя.
2. Используй consumer groups для разных задач: аналитика, логирование, алерты могут читать один и тот же топик независимо.
3. Следи за offset’ами: по умолчанию Kafka фиксирует прогресс чтения, чтобы после рестартов не терять сообщения.
Kafka + Python позволяют строить конвейеры обработки данных, которые легко масштабируются горизонтально. Для начинающего питониста это хороший шаг от “скриптиков” к полноценным потоковым системам.
Представь себе конвейер в заводском цеху: по ленте бесконечно едут детали, а рабочие на разных станциях что‑то с ними делают. Apache Kafka — это примерно такой же конвейер, только для данных. Она позволяет принимать, хранить и отдавать миллионы сообщений в реальном времени. Python здесь может быть “рабочим”, который эти данные обрабатывает.
---
### Основные термины Kafka
- Broker — сервер Kafka, который хранит сообщения.
- Topic — “лента”, куда пишутся сообщения (например,
user_events). - Partition — кусок топика. Именно разделы позволяют обрабатывать сообщения параллельно.
- Producer — отправляет сообщения в Kafka.
- Consumer — читает сообщения из Kafka.
- Consumer group — группа потребителей, которые совместно читают один топик, автоматически деля партиции между собой.
Чем больше партиций у топика и чем больше потребителей в группе, тем выше параллелизм.
---
### Установка клиента для Python
Один из популярных клиентов —
confluent-kafka (тонкая обертка над C-библиотекой):pip install confluent-kafka
---
### Простой producer: отправляем события
from confluent_kafka import Producer
import json
producer = Producer({"bootstrap.servers": "localhost:9092"})
def delivery_report(err, msg):
if err is not None:
print(f"Delivery failed: {err}")
else:
print(f"Delivered to {msg.topic()} [{msg.partition()}] at offset {msg.offset()}")
for user_id in range(1, 6):
event = {"user_id": user_id, "action": "click"}
producer.produce(
topic="user_events",
value=json.dumps(event).encode("utf-8"),
callback=delivery_report
)
producer.flush()
Сообщения попадают в топик
user_events. Kafka сама распределяет их по партициям (по умолчанию — по хешу ключа, если он есть).---
### Параллельное чтение: несколько consumers в одной группе
Ключ к параллельности — использовать одну consumer group и задать топику несколько партиций (например,
3). Тогда, если ты запустишь этот скрипт в нескольких процессах, Kafka раздаст им партиции автоматически.from confluent_kafka import Consumer, KafkaException
import json
consumer = Consumer({
"bootstrap.servers": "localhost:9092",
"group.id": "analytics_group",
"auto.offset.reset": "earliest",
})
consumer.subscribe(["user_events"])
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
continue
if msg.error():
raise KafkaException(msg.error())
event = json.loads(msg.value().decode("utf-8"))
print(
f"Process: handled user={event['user_id']} "
f"from partition={msg.partition()} offset={msg.offset()}"
)
finally:
consumer.close()
Теперь магия:
- Увеличиваешь количество процессов/контейнеров с этим consumer’ом — обработка масштабируется.
- Kafka сама следит, кто какие партиции читает, и перераспределяет их при падении одного из экземпляров.
---
### Практические советы
1. Думай о ключах сообщений: одинаковый ключ → одинаковая партиция → удобно гарантировать порядок для конкретного пользователя.
2. Используй consumer groups для разных задач: аналитика, логирование, алерты могут читать один и тот же топик независимо.
3. Следи за offset’ами: по умолчанию Kafka фиксирует прогресс чтения, чтобы после рестартов не терять сообщения.
Kafka + Python позволяют строить конвейеры обработки данных, которые легко масштабируются горизонтально. Для начинающего питониста это хороший шаг от “скриптиков” к полноценным потоковым системам.
👍1
Основы работы с Memcached и Redis для кэширования данных
Если ваш Python‑код постоянно лезет в базу за одними и теми же данными — вы жжёте процессор и тормозите приложение. В таких случаях на сцену выходят Memcached и Redis — быстрые in‑memory хранилища, идеальные для кэширования.
---
### Зачем нужен кэш
Кэширование — это сохранение заранее вычисленных результатов в память, чтобы не пересчитывать и не запрашивать их повторно. Типичный сценарий:
1. Проверяем кэш.
2. Если данных нет — обращаемся к БД / API.
3. Кладём результат в кэш.
4. В следующий раз берём из кэша за миллисекунды.
---
### Memcached: минималистичный и быстрый
Memcached — это просто распределённый словарь в памяти: ключ–значение, без сложных типов данных.
Установка клиента:
Пример:
Особенности Memcached:
- Нет персистентности: перезапустили — всё забыто.
- Простые типы (строки/байты).
- Идеален как быстрый временный кэш поверх БД.
---
### Redis: швейцарский нож кэширования
Redis умеет больше: строки, списки, множества, хэши, TTL, pub/sub, транзакции и персистентность.
Установка:
Пример кэша с TTL:
Пример использования сложных структур: счётчик просмотров товара:
---
### Что выбрать новичку
- Memcached, если нужен простой, сверхбыстрый кэш без сложных структур и персистентности.
- Redis, если хотите кэш + дополнительные возможности (счётчики, очереди, сессии, персистентность).
Для учебных проектов Redis часто удобнее: он универсален и его легче масштабировать по мере усложнения системы.
Если ваш Python‑код постоянно лезет в базу за одними и теми же данными — вы жжёте процессор и тормозите приложение. В таких случаях на сцену выходят Memcached и Redis — быстрые in‑memory хранилища, идеальные для кэширования.
---
### Зачем нужен кэш
Кэширование — это сохранение заранее вычисленных результатов в память, чтобы не пересчитывать и не запрашивать их повторно. Типичный сценарий:
1. Проверяем кэш.
2. Если данных нет — обращаемся к БД / API.
3. Кладём результат в кэш.
4. В следующий раз берём из кэша за миллисекунды.
---
### Memcached: минималистичный и быстрый
Memcached — это просто распределённый словарь в памяти: ключ–значение, без сложных типов данных.
Установка клиента:
pip install pymemcache
Пример:
from pymemcache.client import base
client = base.Client(("localhost", 11211))
def get_user_profile(user_id: int) -> dict:
cache_key = f"user:{user_id}"
cached = client.get(cache_key)
if cached:
# данные хранятся как bytes; в реальном коде — json.loads(...)
print("from cache")
return eval(cached.decode("utf-8"))
print("from db")
user = {"id": user_id, "name": "Alice"} # тут должна быть реальная БД
client.set(cache_key, str(user).encode("utf-8"), expire=60)
return user
get_user_profile(1)
get_user_profile(1)
Особенности Memcached:
- Нет персистентности: перезапустили — всё забыто.
- Простые типы (строки/байты).
- Идеален как быстрый временный кэш поверх БД.
---
### Redis: швейцарский нож кэширования
Redis умеет больше: строки, списки, множества, хэши, TTL, pub/sub, транзакции и персистентность.
Установка:
pip install redis
Пример кэша с TTL:
import json
from redis import Redis
redis_client = Redis(host="localhost", port=6379, db=0)
def get_product(product_id: int) -> dict:
cache_key = f"product:{product_id}"
cached = redis_client.get(cache_key)
if cached:
print("from cache")
return json.loads(cached)
print("from db")
product = {"id": product_id, "title": "Keyboard", "price": 99.9}
redis_client.set(cache_key, json.dumps(product), ex=120)
return product
get_product(10)
get_product(10)
Пример использования сложных структур: счётчик просмотров товара:
def increment_views(product_id: int) -> int:
key = f"product:{product_id}:views"
return redis_client.incr(key)
print(increment_views(10))
print(increment_views(10))
---
### Что выбрать новичку
- Memcached, если нужен простой, сверхбыстрый кэш без сложных структур и персистентности.
- Redis, если хотите кэш + дополнительные возможности (счётчики, очереди, сессии, персистентность).
Для учебных проектов Redis часто удобнее: он универсален и его легче масштабировать по мере усложнения системы.
👍2
Использование pandas для преобразования и очистки данных
Если вы хоть раз открывали «сырой» CSV-файл, то знаете: данные редко бывают аккуратными. Пропуски, дубли, странные форматы дат — всё это мешает анализу. Здесь на сцену выходит
---
### Загрузка и первый взгляд на данные
Начнём с простого: прочитаем CSV и посмотрим, что внутри.
---
### Преобразование типов и работа с датами
Частая проблема — строки там, где должны быть числа или даты.
Параметр
---
### Очистка пропусков и дубликатов
Пропуски можно либо удалить, либо заполнить осмысленными значениями.
Для числовых столбцов часто используют среднее, медиану или 0 — зависит от задачи:
---
### Создание новых признаков
Pandas позволяет легко добавлять столбцы, основанные на уже существующих.
За пару строк кода можно превратить «сырые» данные в удобный набор признаков для анализа или модели.
---
### Фильтрация и группировка
Комбинация фильтрации и группировки — основа исследовательского анализа.
С помощью
---
Если вы хоть раз открывали «сырой» CSV-файл, то знаете: данные редко бывают аккуратными. Пропуски, дубли, странные форматы дат — всё это мешает анализу. Здесь на сцену выходит
pandas — швейцарский нож для работы с табличными данными в Python.---
### Загрузка и первый взгляд на данные
Начнём с простого: прочитаем CSV и посмотрим, что внутри.
import pandas as pd
df = pd.read_csv("sales.csv")
print(df.head())
print(df.info())
head() показывает первые строки, info() — типы столбцов и наличие пропусков. Уже отсюда часто можно понять, где бардак: например, даты хранятся как object, а суммы — как строки.---
### Преобразование типов и работа с датами
Частая проблема — строки там, где должны быть числа или даты.
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df["date"] = pd.to_datetime(df["date"], errors="coerce")
Параметр
errors="coerce" превращает невозможные значения в NaN. Это удобно: дальше их можно явно обработать, а не ловить таинственные ошибки.---
### Очистка пропусков и дубликатов
Пропуски можно либо удалить, либо заполнить осмысленными значениями.
# Удаляем строки, где нет суммы покупки
df = df.dropna(subset=["amount"])
# Заполняем пропущенный город значением "Unknown"
df["city"] = df["city"].fillna("Unknown")
# Удаляем полные дубликаты строк
df = df.drop_duplicates()
Для числовых столбцов часто используют среднее, медиану или 0 — зависит от задачи:
df["discount"] = df["discount"].fillna(df["discount"].median())
---
### Создание новых признаков
Pandas позволяет легко добавлять столбцы, основанные на уже существующих.
df["year"] = df["date"].dt.year
df["month"] = df["date"].dt.month
df["amount_with_tax"] = df["amount"] * 1.2
За пару строк кода можно превратить «сырые» данные в удобный набор признаков для анализа или модели.
---
### Фильтрация и группировка
Комбинация фильтрации и группировки — основа исследовательского анализа.
# Оставим только заказы после 2023 года и с положительной суммой
filtered = df[(df["date"].dt.year >= 2023) & (df["amount"] > 0)]
# Посчитаем суммарные продажи по городам
city_stats = (
filtered
.groupby("city", as_index=False)["amount"]
.sum()
.rename(columns={"amount": "total_amount"})
)
print(city_stats.head())
С помощью
groupby и агрегирующих функций (sum, mean, count и др.) можно быстро получать сводки и отчёты, не трогая Excel.---
pandas превращает хаотичный CSV в аккуратный, структурированный датафрейм, с которым приятно работать. Чем раньше вы начнёте его использовать, тем меньше времени будете тратить на рутину и тем больше — на сам анализ.👍1
Как настроить асинхронные HTTP‑запросы с aiohttp
Синхронный код в стиле
---
### Установка и базовый пример
Первый асинхронный запрос:
Разбор:
-
-
-
---
### Параллельные запросы
Самая вкусная часть — запуск запросов одновременно:
Все запросы уходят почти одновременно, а ответы обрабатываются по мере готовности. Разница особенно заметна на “медленных” API.
---
### Таймауты и обработка ошибок
Без ограничений можно повесить программу на “вечном” запросе. Добавим таймаут и отловим ошибки:
Ключевые моменты:
-
-
- перехват
---
### Когда стоит переходить на aiohttp
Используйте асинхронные HTTP‑запросы, когда:
- нужно дернуть много URL в короткое время;
- ваш код в основном ждет сети или диска;
- вы пишете асинхронный веб‑скрейпер, бота или микросервис.
Если запрос один‑два —
Синхронный код в стиле
requests.get() удобен, пока запросов мало. Но как только нужно опросить десятки или сотни URL — программа начинает “залипать”. Здесь на сцену выходит aiohttp и asyncio.---
### Установка и базовый пример
pip install aiohttp
Первый асинхронный запрос:
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:
html = await fetch(session, "https://httpbin.org/get")
print(len(html))
asyncio.run(main())
Разбор:
-
async def — объявление корутины;-
await — “подождать, но не блокировать”;-
ClientSession — переиспользует соединения (это важно для производительности).---
### Параллельные запросы
Самая вкусная часть — запуск запросов одновременно:
import asyncio
import aiohttp
URLS = [
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/3",
]
async def fetch_status(session, url):
async with session.get(url) as response:
return url, response.status
async def main():
async with aiohttp.ClientSession() as session:
tasks = [asyncio.create_task(fetch_status(session, url)) for url in URLS]
for task in asyncio.as_completed(tasks):
url, status = await task
print(url, "->", status)
asyncio.run(main())
Все запросы уходят почти одновременно, а ответы обрабатываются по мере готовности. Разница особенно заметна на “медленных” API.
---
### Таймауты и обработка ошибок
Без ограничений можно повесить программу на “вечном” запросе. Добавим таймаут и отловим ошибки:
import asyncio
import aiohttp
from aiohttp import ClientError
async def safe_fetch_json(session, url):
try:
async with session.get(url, timeout=3) as response:
response.raise_for_status()
return await response.json()
except asyncio.TimeoutError:
print("Timeout:", url)
except ClientError as e:
print("ClientError:", url, "->", e)
async def main():
async with aiohttp.ClientSession() as session:
data = await safe_fetch_json("https://httpbin.org/json")
print("Result:", data)
asyncio.run(main())
Ключевые моменты:
-
timeout=3 — запрос не будет длиться бесконечно;-
raise_for_status() — выбросит исключение при 4xx/5xx;- перехват
ClientError — базовый класс большинства сетевых ошибок в aiohttp.---
### Когда стоит переходить на aiohttp
Используйте асинхронные HTTP‑запросы, когда:
- нужно дернуть много URL в короткое время;
- ваш код в основном ждет сети или диска;
- вы пишете асинхронный веб‑скрейпер, бота или микросервис.
Если запрос один‑два —
requests проще. Но как только вы упираетесь в “ожидание сети”, aiohttp + asyncio дает очень ощутимый прирост скорости, не усложняя код слишком сильно.❤3
Создание и управление новой базой данных SQLite в Python
SQLite — идеальная отправная точка для тех, кто хочет начать работать с базами данных, не устанавливая сервер и не настраивая сложные системы. Всё хранится в одном файле, а в Python уже есть встроенный модуль
Разберём базовые шаги: создание БД, таблиц, вставка, выборка и обновление данных.
---
### 1. Подключение и создание базы
Если файла базы данных нет,
---
### 2. Создание таблицы
Создадим таблицу для статей блога:
---
### 3. Вставка данных
Добавим новую запись:
Обрати внимание на
---
### 4. Чтение данных
Вытащим все статьи:
---
### 5. Обновление и удаление
Изменим заголовок и удалим запись:
---
### 6. Акуратное закрытие соединения
Либо использовать контекстный менеджер:
В этом случае
---
SQLite +
SQLite — идеальная отправная точка для тех, кто хочет начать работать с базами данных, не устанавливая сервер и не настраивая сложные системы. Всё хранится в одном файле, а в Python уже есть встроенный модуль
sqlite3.Разберём базовые шаги: создание БД, таблиц, вставка, выборка и обновление данных.
---
### 1. Подключение и создание базы
Если файла базы данных нет,
sqlite3 создаст его автоматически:import sqlite3
conn = sqlite3.connect("blog.db") # создаем/открываем файл базы
cursor = conn.cursor()
conn — это соединение, cursor — объект для выполнения SQL-запросов.---
### 2. Создание таблицы
Создадим таблицу для статей блога:
cursor.execute("""
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
IF NOT EXISTS защитит от ошибки при повторном запуске скрипта.---
### 3. Вставка данных
Добавим новую запись:
new_post = ("First post", "This is my first post content.")
cursor.execute(
"INSERT INTO posts (title, content) VALUES (?, ?)",
new_post
)
conn.commit()
Обрати внимание на
? — это параметризованный запрос. Так безопаснее и защищает от SQL-инъекций.---
### 4. Чтение данных
Вытащим все статьи:
cursor.execute("SELECT id, title, created_at FROM posts")
rows = cursor.fetchall()
for row in rows:
post_id, title, created_at = row
print(post_id, title, created_at)
fetchall() возвращает список кортежей. Для больших объёмов данных выгоднее использовать fetchone() в цикле.---
### 5. Обновление и удаление
Изменим заголовок и удалим запись:
cursor.execute(
"UPDATE posts SET title = ? WHERE id = ?",
("Updated title", 1)
)
cursor.execute(
"DELETE FROM posts WHERE id = ?",
(2,)
)
conn.commit()
---
### 6. Акуратное закрытие соединения
conn.close()
Либо использовать контекстный менеджер:
import sqlite3
with sqlite3.connect("blog.db") as conn:
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM posts")
print(cursor.fetchone())
В этом случае
commit() и close() произойдут автоматически.---
SQLite +
sqlite3 — это минимальный, но мощный набор, чтобы почувствовать себя создателем настоящих приложений с базой данных: от простого блога до небольших утилит и заметочников. Главное — аккуратная работа с запросами и понимание, что всё это уже доступно «из коробки» в Python.👍2
Введение в управление сессиями пользователей с помощью Flask
Когда вы пишете веб‑приложение, быстро возникает вопрос: как «запомнить» пользователя между запросами? HTTP сам по себе «ничего не помнит» — каждый запрос живет отдельно. Здесь на сцену выходят сессии.
Во Flask сессия — это обычный словарь
Начнем с минимального примера «ручного входа»:
Что здесь важно:
-
-
-
-
Flask хранит содержимое сессии в зашифрованном cookie, поэтому:
1. Не кладите туда большие данные (лимит cookie обычно до 4 КБ).
2. Не храните критически важные секреты (например, пароли в открытом виде).
3. Обязательно ставьте нормальный
Чтобы чуть усложнить пример, добавим флаг администратора:
Так шаг за шагом можно строить авторизацию, роли, корзину покупок, настройки пользователя — всё это основано на сессиях. Flask делает работу с ними максимально простой: по сути вы просто модифицируете словарь, а фреймворк сам связывает его с конкретным пользователем.
Когда вы пишете веб‑приложение, быстро возникает вопрос: как «запомнить» пользователя между запросами? HTTP сам по себе «ничего не помнит» — каждый запрос живет отдельно. Здесь на сцену выходят сессии.
Во Flask сессия — это обычный словарь
session, который привязан к пользователю через cookie. Данные сессии шифруются с помощью SECRET_KEY, поэтому значение ключа должно быть сложным и храниться в секрете.Начнем с минимального примера «ручного входа»:
from flask import Flask, session, redirect, url_for, request
app = Flask(__name__)
app.secret_key = "change_this_secret_key"
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get("username")
# Здесь могла бы быть проверка пароля
session["user"] = username
return redirect(url_for("profile"))
return """
<form method="post">
<input name="username" placeholder="Username">
<button type="submit">Login</button>
</form>
"""
@app.route("/profile")
def profile():
user = session.get("user")
if not user:
return redirect(url_for("login"))
return f"Hello, {user}! This is your profile."
@app.route("/logout")
def logout():
session.pop("user", None)
return redirect(url_for("login"))
if __name__ == "__main__":
app.run(debug=True)
Что здесь важно:
-
session работает почти как обычный словарь.-
session["user"] = username — «залогинили» пользователя.-
session.get("user") — проверяем, авторизован ли он.-
session.pop("user", None) — «разлогин».Flask хранит содержимое сессии в зашифрованном cookie, поэтому:
1. Не кладите туда большие данные (лимит cookie обычно до 4 КБ).
2. Не храните критически важные секреты (например, пароли в открытом виде).
3. Обязательно ставьте нормальный
SECRET_KEY (случайную строку, а не 123).Чтобы чуть усложнить пример, добавим флаг администратора:
@app.route("/set_admin")
def set_admin():
session["is_admin"] = True
return "Admin mode enabled"
@app.route("/admin")
def admin_panel():
if not session.get("is_admin"):
return "Access denied", 403
return "Welcome to admin panel"
Так шаг за шагом можно строить авторизацию, роли, корзину покупок, настройки пользователя — всё это основано на сессиях. Flask делает работу с ними максимально простой: по сути вы просто модифицируете словарь, а фреймворк сам связывает его с конкретным пользователем.
👍1