Открытый канал ID 70411662549182

Библиотека питониста | Python, Django, Flask

Реклама: t.me/tproger_sales_bot

Каналов в рубрике
1 733
Место этого канала
№ 418
Открыть рубрику →
Открыть в MAX

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

Стек и очередь в Python: и почему list не всегда правильный выбор

Большинство питонистов используют list для всего подряд. 

Но у list есть конкретная асимптотика, и игнорировать её — значит писать медленный код.

📋 Stack (LIFO) → list

append() и pop() работают за O(1). Список оптимизирован именно для работы с концом:

stack = []
stack.append(1)
stack.append(2)
stack.append(3)
stack.pop()  # → 3
stack.pop()  # → 2

А вот insert(0, x) и pop(0) — это O(n). Каждый раз сдвигается весь массив:

# Медленно — 200k итераций занимают несколько секунд
for n in range(200_000):
    numbers.insert(0, n)

# Быстро — то же количество итераций, мгновенно
for n in range(200_000):
    numbers.append(n)



🔄 Queue (FIFO) → deque

Если нужна очередь — берите collections.deque. Операции с обоих концов работают за O(1):

from collections import deque

queue = deque()
queue.append(1)    # добавить справа
queue.append(2)
queue.append(3)
queue.popleft()    # → 1 (первый вошёл — первый вышел)
queue.popleft()    # → 2

deque — это double-ended queue. Можно добавлять и удалять с обоих концов эффективно:

queue.appendleft(0)   # добавить слева — O(1)
queue.pop()            # удалить справа — O(1)
queue.popleft()        # удалить слева — O(1)



Правило одной
строкой

Нужен стек → list. Нужна очередь → deque. Использовать list как очередь через pop(0) — это O(n) на каждую операцию.
Просмотры: 182
Перейти в пост Открыть в MAX Сообщить о неточности
Какой тип данных для иммутабельных структур самый быстрый в Python

NamedTuple, dataclass, attrs, msgspec — все решают одну задачу, но с очень разной стоимостью при старте программы. Автор сделал детальный бенчмарк
. Вот что получилось.


📊 Три уровня производительности (warm start)

Быстрые (~7-12 µs на тип):
— native slots — просто __slots__
— msgspec.Struct — сериализация + struct в одном
— record-type (C) — прототип C-расширения

Средние (~76-96 µs, в ~8 раз медленнее):
— NamedTuple — то что большинство использует по умолчанию
— record-type — декоратор от Brett Cannon

Медленные (~200-370 µs, в ~20-30 раз медленнее):
— dataclass, frozen dataclass
— attrs


🔍 Почему такая разница

Всё упирается в количество методов которые генерируются при создании типа:

— native slots и C-расширения: ничего не генерируют → быстро
— NamedTuple: генерирует один __new__ через eval → средне
— dataclass: генерирует __init__, __repr__, __eq__ за один раз, frozen добавляет ещё три → медленно


💾 Память на экземпляр

native slots → 64 байта
NamedTuple → 88 байт (tuple overhead)
msgspec → 64 байта
attrs → 80 байт
dataclass → 64 байта

frozen=True не меняет размер в памяти — это только флаг на уровне записи, не структуры.


⚡ Время создания экземпляра

msgspec → ~62 ns
native → ~87 ns
NamedTuple → ~138 ns
attrs → ~209 ns
frozen dc → ~224 ns

Если пишете CLI или инструменты где важен startup time — NamedTuple не такой «бесплатный» как кажется. msgspec быстрее после ~229 типов (warm) но тянет за собой 19ms импорта. Для большинства проектов NamedTuple всё ещё разумный выбор — но теперь вы знаете цену.
Просмотры: 151
Перейти в пост Открыть в MAX Сообщить о неточности
WeakKeyDictionary: как хранить данные «рядом с объектом» без прямой записи в атрибуты

Классический паттерн: хочется прикрепить доп. данные к объекту — делаешь obj._cache = .... Но у этого три проблемы:

— не работает для built-in типов и slotted классов
— имена атрибутов могут конфликтовать с другим кодом
— атрибуты вылезают в vars() и других местах где не ждёшь


🔑 Решение — WeakKeyDictionary

from weakref import WeakKeyDictionary
import ast

used_names_cache: WeakKeyDictionary[ast.Module, set[str]] = WeakKeyDictionary()

def all_used_names(module: ast.Module) -> set[str]:
try:
return used_names_cache[module]
except KeyError:
pass

names = set()
# ... заполняем set
used_names_cache[module] = names
return names

Данные живут «здесь», а не на объекте. Производительность O(1) как у обычного атрибута.

Главное преимущество: как только объект перестаёт существовать в остальном коде — запись в словаре тоже удаляется автоматически. Нет утечек памяти.


⚠️ Почему не functools.cache?

@cache
def all_used_names(module): ...

functools.cache хранит сильные ссылки на аргументы. Даже если module больше нигде не используется — кэш держит его живым и не даёт GC освободить память.


📋 Два условия для объекта

Объект должен быть hashable — выполняется по умолчанию если не переопределён __eq__ без __hash__.

Объект должен поддерживать weak reference — большинство user-defined классов поддерживают. Для slotted классов нужно явно добавить:

class Train:
__slots__ = ("__weakref__", "wheels", "engine")
Просмотры: 111
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
FastAPI Cloud вышел в публичную бету

Деплой существующего FastAPI-приложения:

uv run fastapi deploy

Новое приложение:

uvx fastapi-newuv run fastapi deploy🚀

Что включено из коробки
— HTTPS по умолчанию — автоматические TLS-сертификаты
— Автоскейлинг — растёт с трафиком, scale to zero в разработке
— Zero-downtime деплои — новые версии раскатываются постепенно
— Авто-верификация — если что-то сломалось, остаётся последняя рабочая версия
— GitHub интеграция — push в main = автодеплой, без CI-конфигов
— БД из коробки — Neon (Postgres), Redis Cloud, Supabase в пару кликов
— Логи, метрики, переменные окружения, кастомные домены
— VS Code расширение

⚙️ GitHub Actions если нужно



fastapi cloud setup-ci

Команда сама создаёт deploy tokens, прописывает их как GitHub secrets и генерирует workflow файл.

🤖 Про агентов

CLI спроектирован так чтобы AI-агенты могли работать с ним из терминала — деплоить, читать логи, обновлять переменные, дебажить — без кастомных интеграций. Поддержка JSON-вывода, явные параметры.

Вместо стен YAML — одна команда fastapi deploy. Это и есть deployment surface для агентов.

Ссылка на сайт
Просмотры: 130
Перейти в пост Открыть в MAX Сообщить о неточности
👍 classmethod, staticmethod или instance method: простое правило выбора

Смотрите что метод реально использует:
— нужен self → instance method
— нужен cls, но не конкретный экземпляр → @classmethod
— не нужно ни то ни другое → @staticmethod


🔵 Instance method — работа с состоянием объекта

Всё что читает или меняет атрибуты конкретного экземпляра. Стандарт по умолчанию.


🟢 @classmethod — альтернативные конструкторы

Python не поддерживает перегрузку init, поэтому когда нужно создать объект из разных источников — каждый способ становится classmethod:

# из стандартной библиотеки
date.today()
date.fromtimestamp(1718539200)
date.fromisoformat("2026-06-16")

Все возвращают date, но стартуют из разного сырья. Ещё один хороший кейс — реестры и кэши на уровне класса:

class Handler:
_registry: dict[str, type["Handler"]] = {}

@classmethod
def register(cls, name: str, handler: type["Handler"]) -> None:
cls._registry[name] = handler

🟡 @staticmethod — утилита без контекста

Чистая функция которая живёт в классе для удобства неймспейса. Не трогает ни self ни cls:

class Color:
@staticmethod
def hex2rgb(hex_value: str) -> tuple[int, int, int]:
return tuple(int(hex_value[i:i+2], 16) for i in (1, 3, 5))

Сигнал: если staticmethod можно вынести на уровень модуля и ничего не сломается — возможно, так и стоит сделать. Это не плохой паттерн, просто честный вопрос.
Просмотры: 123
Перейти в пост Открыть в MAX Сообщить о неточности
👍 ArchUnit для Python:  архитектурные правила как юнит-тесты

Python не заботится о том как вы организуете код. Нет компилятора который закричит когда route handler импортирует напрямую из слоя базы данных. Нет ошибки при циклической зависимости между модулями.

Всё работало пока проект не вырос. А потом кто-то импортировал sqlalchemy прямо в Pydantic-схему — потому что так быстрее.

ArchUnitPython
решает это: архитектурные правила живут рядом с обычными тестами и запускаются в pytest.

🚫 Запретить зависимости между слоями


from archunitpython import project_files, assert_passes
def test_presentation_should_not_depend_on_database():
    rule = (
        project_files("src/")
        .in_folder("**/presentation/**")
        .should_not()
        .depend_on_files()
        .in_folder("**/database/**")
    )
    assert_passes(rule)

🔄 Запретить циклические зависимости


def test_no_circular_dependencies():
    rule = project_files("src/").should().have_no_cycles()
    assert_passes(rule)

Когда правило нарушается — тест падает с понятным сообщением. Никаких отдельных конфигов и команд.

✅ Что проверяет

— направление зависимостей между слоями
— циклические зависимости
— нарушения именования
— превышение размера файлов
— внешние модули в неположенных местах

pip install archunitpython
Просмотры: 121
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Python 3.15.0 beta 3: что нас ждёт в октябре

Вышла третья бета Python 3.15. Финальный релиз запланирован на октябрь 2026. Самое интересное что добавят:

— Ленивые импорты (PEP 810) — модули загружаются только когда реально нужны. Стартап тяжёлых пакетов типа pandas/numpy станет заметно быстрее

— frozendict как встроенный тип (PEP 814) — неизменяемый словарь наконец в стандартной библиотеке

— Unpacking в comprehensions (PEP 798):

# теперь можно такflat = [x for xs in nested for *x, _ in [xs]]

— UTF-8 по умолчанию (PEP 686) — больше никаких сюрпризов при чтении файлов на разных ОС

Производительность

JIT-компилятор значительно улучшен: +8-9% на x86-64 Linux и +12-13% на AArch64 macOS по сравнению с интерпретатором без JIT.

Инструменты

— Встроенный профайлер Tachyon (PEP 799) — высокочастотный статистический сэмплер прямо в стандартной библиотеке

— Frame pointers включены по умолчанию (PEP 831) — лучше работают внешние профайлеры типа py-spy и perf

Типизация

— TypedDict с типизированными дополнительными ключами (PEP 728)
— sentinel как встроенный тип (PEP 661)
— TypeForm для аннотации самих типов (PEP 747)

Следующая бета — 18 июля, первый RC — 4 августа.

🔗 Ссылка на новость
Просмотры: 115
Перейти в пост Открыть в MAX Сообщить о неточности
Hydra: конфигурация ML-экспериментов без боли

Типичная проблема: у вас ML-проект, конфиги размножились, и вы передаёте гиперпараметры через argparse или хардкодите в скриптах. Hydra решает это элегантно.

Главная идея: конфиги — это YAML-файлы которые можно составлять, наследовать и переопределять прямо из командной строки.

Запуск с разными параметрами без изменения кода:

python train.pydataset model=resnet =imagenet lr=0.001python train.pyaset model=vit dat=cifar10 lr=0.0001

Multirun — запуск сетки экспериментов одной командой:

python train.py.0001 mo -m lr=0.001,0del=resnet,vit# запустит 4 эксперимента автоматически

Конфиги можно композировать из отдельных файлов:

configs/  model/    resnet.yaml    vit.yaml  dataset/    imagenet.yaml    cifar10.yaml  train.yaml  ← собирает всё вместе

Популярные связки с Hydra:
— lightning-hydra-template — готовый шаблон PyTorch Lightning + Hydra для быстрого старта
— hydra-zen — Pythonic API для динамической генерации конфигов
— hydra-torch — type-safe конфиги для PyTorch компонентов

pip install hydra-core --upgrade

Если вы ещё управляете экспериментами через argparse или захардкоженные словари — Hydra стоит попробовать.

➡️ Github
Просмотры: 121
Перейти в пост Открыть в MAX Сообщить о неточности
✔️ Тест прошёл, но не потому что мок сработал

Классическая ловушка с моками в Python: тест зелёный, но реальный API всё равно вызывается. Вот как это происходит и как проверить что мок реально перехватил вызов.

Симптом

Тест на исключение при невалидной валюте проходит. Но в моке настроен ответ "result": "success" — который никогда не выбросит исключение. Как тест зелёный?

Реальный API вернул ошибку для несуществующей валюты «CTM». Мок вообще не сработал.

Как доказать что мок перехватил вызов

with pytest.raises(CurrencyConversionError):
convert_currency(
amount=Decimal("1.00"),
from_currency="CAD",
to_currency="CTM",
)

mock_get.assert_called_once() # если упал — мок не перехватил, бил реальный API

assert_called_once() — не опциональная проверка, а обязательная часть теста когда вы мокаете внешние вызовы.

Главное правило: патчить там где имя используется, не где определено

# модуль делает: import requests
# правильно:
mocker.patch("myapp.utils.currency.requests.get")

# если модуль делает: from requests import get
# то только так:
mocker.patch("myapp.utils.currency.get")
# requests.get здесь не перехватит ничего

Это самая частая причина почему мок «не работает».

Итоговый тест с pytest-mock

def test_bad_currency_raises(self, mocker):
mock_get = mocker.patch("myapp.utils.currency.requests.get")
mock_get.return_value.json.return_value = {
"result": "error",
"error-type": "unknown-code",
}

with pytest.raises(CurrencyConversionError):
convert_currency(Decimal("1.00"), "CAD", "CTM")

mock_get.assert_called_once()

Когда мок — не лучший инструмент

Если каждый тест завязан на конкретный import path — это тест реализации, не поведения. Альтернатива: адаптер-класс для внешнего вызова + fake-реализация + dependency injection. Тогда не нужно патчить вообще.
Просмотры: 122
Перейти в пост Открыть в MAX Сообщить о неточности
▶ видео
📘 Tricky Python: квиз из самых коварных ловушек языка

20 вопросов, каждый раз случайная выборка из базы WTFPython.

В конце показывает объяснение каждой ловушки и даёт карточку с результатом — можно делиться.

➡️ Ссылка на квиз
Просмотры: 128
Перейти в пост Открыть в MAX Сообщить о неточности
Вся лента — после бесплатной регистрации
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «Библиотека питониста | Python, Django, Flask» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти