Полный Дзен Пайтона в одном канале Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Сайт: https://tprg.ru/site Регистрация в перечне РКН: https://tprg.ru/xZOL
Типичный день вайбкодера выглядит так.
#постИИрония
Отслеживание неиспользуемых ключей в словаре Python
Словари — это фундаментальная структура данных, используемая для хранения пар «ключ-значение». В большинстве случаев мы просто читаем и записываем значения по ключам, не задумываясь о том, какие ключи были запрошены в процессе выполнения программы, а какие так и остались неиспользованными. Однако иногда в разработке возникает задача понять, какие ключи словаря так и не были использованы.
Представим, что у вас есть словарь с множеством параметров, который передаётся в функцию или класс. Вы хотите убедиться, что ваша логика действительно «потрогала» все ключи, и не осталось параметров, которые вы передали, но не использовали. Это особенно актуально, если словарь — это некий набор опций или конфигураций.
Без специальных инструментов проверить, какие ключи словаря не использовались, довольно сложно. Стандартный словарь в Python не хранит никакой информации о том, обращались ли к конкретному ключу.
Решения: словарь с учётом использования ключей
Для решения этой задачи можно создать класс-обёртку над обычным словарём, который при каждом запросе ключа будет отмечать этот ключ как «использованный».
Основные требования к такой структуре:
— При запросе значения по ключу отмечать ключ как использованный;
— Предоставлять метод, возвращающий ключи, к которым не обращались;
— Максимально просто и удобно использовать вместо обычного словаря.
Реализация: UsedDict
class UsedDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._used_keys = set()
def __getitem__(self, key):
self._used_keys.add(key)
return super().__getitem__(key)
def get_unused_keys(self):
return set(self.keys()) - self._used_keys
dict
, чтобы сохранить привычный интерфейс;_used_keys
, в котором будем хранить все ключи, к которым обращались;__getitem__
, который вызывается при чтении значения по ключу mydict[key]
. В этом методе сначала отмечаем ключ как использованный, а затем возвращаем значение;get_unused_keys
, который возвращает разницу между всеми ключами словаря и теми, которые использовались.
config = UsedDict({
"host": "localhost",
"port": 8080,
"debug": True,
"timeout": 30
})
print(config["host"]) # используется
print(config["port"]) # используется
unused = config.get_unused_keys()
print("Неиспользованные ключи:", unused)
# Выведет: Неиспользованные ключи: {'debug', 'timeout'}
crudadmin | Минималистичная админка для FastAPI
Симпатичный минималистичный GUI для самописных API. Поддерживает различные бэкенды для сессий (Redis, Memcached и БД). Встроенные механизмы защиты включают фильтрацию IP, защиту от DDoS-атак и подробный журнал событий.
Консоль доступна по адресу /admin в тёмной и светлой темах.
Цена: бесплатно
Репозиторий проекта
#инструмент
Молчаливый «провал» INSERT
Вы запускаете SQL-запрос INSERT
, и вроде всё просто. Нет ошибок. Но и данные не вставлены. Звучит странно? Такое действительно может случиться с PostgreSQL — и случается чаще, чем хотелось бы.
Как можно вставить данные и не вставить одновременно?
Когда INSERT
не срабатывает, первое, что приходит в голову — ошибка. Но PostgreSQL умеет «глотать» такое — ведь вы сами его об этом попросили.
Виновник — ON CONFLICT DO NOTHING
INSERT INTO users (id, email)
VALUES (42, 'user@example.com')
ON CONFLICT (id) DO NOTHING;
id
, ничего не делай". И PostgreSQL по умолчанию так и поступает.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE,
username TEXT UNIQUE
);
INSERT INTO users (email, username)
VALUES ('user@example.com', 'johnny');
username = 'johnny'
уже существует, но email
ещё нет?ON CONFLICT
(email)
говорит PostgreSQL: «молчи, если конфликт по email
, но бросай ошибку, если конфликт по чему-то ещё».
ON CONFLICT DO NOTHING
rowcount
после запроса. В Python/psycopg2, например:
cursor.execute(sql, values)
if cursor.rowcount == 0:
print("Nothing inserted!")
RETURNING
и логируйте:
INSERT INTO users (email, username)
VALUES ('user@example.com', 'johnny')
ON CONFLICT DO NOTHING
RETURNING id;
DO UPDATE
, можно добавить логи в `UPDATE`-часть или сохранять «причину отказа» отдельно.py-pglite | PostgreSQL прямо через import
Инструмент для тестов с настоящим PostgreSQL без необходимости поднимать сервер. Он запускается за пару секунд прямо из Python-кода, без Docker и лишней настройки. Полностью совместим с SQLAlchemy, Django ORM, psycopg, asyncpg и поддерживает расширения вроде pgvector.
Цена: бесплатно
На PyPi
#инструмент
@zen_of_python
Zephyr | Действительно ВАШ умный девайс
Этот питонический фреймворк поддерживает 750+ материнских плат и делает устройства умными. Пишите свою логику и деплойте на плату: создатели стремились сделать процесс проще, чем у Arduino.
Цена: бесплатно
Сайт проекта
@prog_tools
Вопросы подписчиков
Zen of Python поддерживает новоприбывших (и не только) в особой рубрике. Как это работает:
— Спрашивайте что угодно (в комментариях под этим постом), связанное с Python. Здесь нет плохих вопросов!
— Сообщество вас поддержит. Самые интересные вопросы мы разберём в отдельном посте;
#вопросы_новичков
@zen_of_python
Type Hinting vs. Type Checking vs. Data Validation: в чём разница?
Python — это язык с динамической типизацией («тип переменной определяется во время выполнения программы»). Это даёт большую гибкость, но одновременно приводит к ошибкам. Чтобы справляться с этим, разработчики используют три инструмента: аннотации типов, проверка типов и валидация данных. У каждого из них своя цель.
Type Hinting — подсказки, а не контроль
Аннотации типов (Type Hinting) — это способ добавить метаинформацию о типах данных, которую Python сам по себе не использует для исполнения кода:
def create_user(first_name: str, last_name: str, age: int) -> dict:
return {"first_name": first_name, "last_name": last_name, "age": age}
mypy your_script.py
create_user("John", "Doe", "38") # строка, а не int
error: Argument "age" to "create_user" has incompatible type "str"; expected "int"
if not isinstance(age, int):
raise TypeError("Age must be an integer")
@validate_call
:
from pydantic import validate_call
@validate_call
def create_user(first_name: str, last_name: str, age: int) -> dict:
return {"first_name": first_name, "last_name": last_name, "age": age}
create_user("John", "Doe", "38") # строка
1 validation error for create_user
age
Input should be a valid integer (type=type_error.integer)
flowshow | отслеживайте задачи с графами
Предоставляет декоратор @task
, который превращает обычную функцию в «таску» с автоматическим сбором метаданных.
Обеспечивает удобный визуальный интерфейс: после запуска main_job()
можно вызвать main_job.plot()
или main_job.last_run.render()
, чтобы увидеть граф выполнения задач, время начала и окончания, входы и выходы, ошибки, логи и количества повторных запусков.
Жизнь в условиях проектов с асинхронностью в том числе станет чуточку легче.
На PyPi
#инструмент
@zen_of_python
great-tables | Make Tables Great Again
Создатель этого репозитория напоминает нам, что у грамотной HTML-таблицы, помимо тела, есть еще (под)заголовок, футер и объединенные ячейки. Забытые возможности <table>...
Цена: бесплатно
Репозиторий проекта
#инструмент
@zen_of_python
Немного безумные способы определения функций
Мы привыкли определять функции с помощью ключевого слова def
. Однако Python как язык куда глубже и гибче, чем может показаться на первый взгляд. Существует несколько способов создать функцию — от практичных до откровенно абсурдных.
Lambda-функции — минимализм в действииlambda
позволяет создавать анонимные функции в одну строку. Это удобно, когда функция короткая и используется "на лету", например, в map()
или filter()
. Lambda-функции не могут содержать сложную логику или много выражений — только одно выражение, без return
и вложенных блоков:
multiply_by_three = lambda x: x * 3
print(multiply_by_three(5))
functools.partial
functools.partial
можно создавать функции с уже предзаданными аргументами:
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
print(square(5)) # 25
def print_result(fmt):
def decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(fmt.format(result))
return result
return wrapper
return decorator
@print_result("Результат: {}")
def double(x):
return x * 2
double(4)
__call__
__call__
. Таким образом, вы можете создавать функции как объекты с состоянием:
class Greeter:
def __call__(self, name):
print(f"Hello, {name}!")
greet = Greeter()
greet("Bob")
exec()
exec()
выполняет строку как код Python. Да, вы можете определять функции с его помощью.
code = '''
def add(x):
return x + 10
'''
exec(code)
print(add(5)) # 15
eval()
eval()
— ещё один способ выполнить строку кода, но только если это выражение, а не целый блок.
add = eval("lambda x: x + 10")
print(add(3)) # 13
exec()
.types.new_class
types.new_class()
можно создавать callable-объекты (через `__call__`) на лету.
import types
def class_body(ns):
ns['__call__'] = lambda self, x: x * 2
DynamicFunction = types.new_class("DynamicFunction")
class_body(DynamicFunction.__dict__)
func = DynamicFunction()
print(func(6)) # 12
mutmut | Мутационные тесты
Mutation Testing — это метод, при котором в ваш исходный код вносятся небольшие изменения (мутации), и затем запускаются ваши тесты.
Цель: проверить, насколько эффективно тесты обнаруживают ошибки.
Утилита вносит мутации в ваш код (на уровне исходников), запускает ваши юнит-тесты после каждой мутации. Затем помечает мутации:
— ✅ Killed (тест поймал баг);
— ❌ Survived (мутация выжила).
Такое особенно важно, если вы работаете в сфере безопасности, финансов.
Цена: бесплатно
Репозиторий проекта
#инструмент
@zen_of_python
Еще немного форсим питонов
#кек
@zen_of_python
🙈 — Если не ожидал такого в канале про ЯП
Я не думаю, что кто-нибудь вообще может остановить Python ЗА ПРЕВЫШЕНИЕ СКОРОСТИ
@ithumor
Вопросы подписчиков
Zen of Python поддерживает новоприбывших (и не только) в особой рубрике. Как это работает:
— Спрашивайте что угодно (в комментариях под этим постом), связанное с Python. Здесь нет плохих вопросов!
— Сообщество вас поддержит. Самые интересные вопросы мы разберём в отдельном посте;
#вопросы_новичков
@zen_of_python
MCP или еще один повод уважать Anthropic
Сегодня всё больше разработчиков задумываются о том, как подключить большие языковые модели (LLM) к своим инструментам и данным. Но сталкиваются с кучей проблем: модели изолированы, не понимают, что делает API, и не могут просто так «пойти» в интернет. И вот здесь появляется MCP (Model Context Protocol).
Это открытый стандарт, созданный Anthropic. ОН решает ключевую проблему: как дать LLM доступ к внешним данным и инструментам, не ломая их внутреннюю безопасность.
Да, у нас есть RESTful API. Но:
— Большинство LLM работают в «песочнице» без доступа в интернет;
— Даже если бы доступ был, модель не знает, как вызвать ваш API, какие параметры использовать и как интерпретировать ответ.
MCP решает эту задачу: он описывает, что делает ваш сервис, как с ним работать и что возвращается в ответ.
Три типа возможностей
1. Resources — данные, которые можно "прочитать", аналог GET-запросов
2. Tools — функции, которые можно вызвать (например, поиск видео)
3. Prompts — шаблоны запросов, помогающие пользователю формировать нужный вызов.
Пример: YouTube
Структура:
1. Модуль YouTube-поиска — обёртка над пакетом youtube-search
2. MCP-сервер — оборачивает этот модуль и превращает его в доступный инструмент для LLM.
def search_youtube(query, max_results):
# Используем youtube_search
...
return result_dict
from fast_mcp import FastMCP
server = FastMCP(name="videos")
server.add_tool("get_videos", search_youtube)
get_videos()
, передав строку запроса — и получить отформатированный список роликов.fast_mcp
.
from fast_mcp.contrib.fastapi import convert_app_to_mcp
app = FastAPI()
# ... API endpoints
mcp_server = convert_app_to_mcp(app)
{
"name": "YouTube Videos",
"command": "uv",
"args": {
"dir": "~/youtube_service",
"file": "run_mcp.py"
}
}
Комментарии в коде: зло или спасение?
Комментарий может не только объяснить код, но и быть бесячим. Грамотно написанные пометки значительно упрощают код-ревью. Кроме того, LLM'ки вроде GitHub Copilot используют комментарии как промты, а это сплошная экономия времени. В статье на Tproger порассуждали, где заканчивается польза и начинается вред от комментариев — и как найти правильный баланс.
#основы
@zen_of_python
Не понимаю, как я это упустил: Microsoft раскатила расширение, которое превращает VS Code в полноценную IDE для работы с PostgreSQL, без переключений между тулзами 👍
Внутри всё, что нужно:
• Визуализация схемы базы прямо в IDE.
• IntelliSense с автокомплитом и подсветкой и форматированием SQL-запросов.
• Запуск PostgreSQL в Docker.
• Быстрое подключение к любой базе (локально, в облаке).
• История запросов для быстрого повторного запуска.
• Просмотр и управление объектами БД.
• История запросов и запуск psql прямо из VS Code.
• Интеграция с GitHub Copilot — AI пишет и объясняет SQL
Поставить можно тут
pyrefly | Ну очень быстрый тайпчекер
В Meta (организация признана экстремистской в РФ) релизнули инструмент для проверки типов данных на базе Rust.
Он аналогичен mypy
, но сделано с упором на производительность. Это быстрая альтернатива для больших кодовых баз.
Взгляните на простой пример:
def greet(name: str) -> str:
return "Hello, " + name
def add(a: int, b: int) -> int:
return a + b
result = add(1, "2") # Ошибка: "2" — это str, а не int
print(result)
pyrefly
как pre-commit-хук. Основы PostgreSQL для начинающих: от установки до первых запросов
PostgreSQL — одна из самых мощных и популярных СУБД. Если вы только начинаете разбираться с ней, у нас есть понятный гайд: как всё установить на любую ОС, создать первую базу данных и выполнить базовые SQL-запросы. Заодно разобрали ключевые плюсы этой системы.
Бонусом: забирайте шпаргалку по БД и подборку игр для прокачки SQL-скиллов
Сохраняйте годноту 👍
Виды компьютерных сетей
Белый хакер разложил по полочкам, какие бывают топологии систем: кольцо, шина, звезда, WLAN, WAN.
Суперпонятная статья для новичков и не только: вы точно почерпнете для себя что-то новое.
#основы
@zen_of_python
PEP 734: Параллелизм без multiprocessing
Запланировано добавление нового стандартного модуля concurrent.interpreters
. Он будет управлять несколькими изолированными подинтерпретаторами внутри одного процесса.
Каждый подинтерпретатор имеет свой собственный GIL, то есть код может действительно выполняться параллельно (в отличие от обычных потоков). Нет накладных расходов на создание отдельных процессов и межпроцессное взаимодействие.
Уже сейчас доступен в виде пакета на PyPI: interpreters-pep-734
, который можно использовать с Python 3.12+.
#инструмент
@zen_of_python
🙉 — Если лучше не видеть, как это работает
Разжигаем огонь... вашей страсти к Python
Проект Kindling Projects предлагает начинающим программистам идеи для небольших проектов на Python, которые достаточно просты для освоения, но при этом позволяют развивать навыки и проявлять креативность.
Сотни несложных утилит, игр, классических кодерских задач, клонов популярных сервисов и проч.
#инструмент
@zen_of_python
Плейлист по изучению питона
Вместо индусов ChatGPT / Cursor
#кек
@zen_of_python