Python-секция на собеседовании редко проверяет, помните ли вы синтаксис, — его подскажет любой редактор. Проверяют другое: понимаете ли вы, что происходит под капотом, и умеете ли выбирать инструмент под задачу. Ниже — реальные вопросы по темам с краткими ориентирами, что именно хочет услышать интервьюер. Не заучивайте формулировки: важно проговаривать своими словами и с примерами из практики.

Как устроена Python-секция

Технические интервью на middle/senior обычно складываются из трёх частей. Теория — вопросы на понимание языка и CPython: GIL, модель памяти, дескрипторы. Лайвкодинг — задача на структуры данных или небольшой практический кейс (распарсить, агрегировать, написать декоратор), где смотрят не только на результат, но и на то, как вы рассуждаете. Вопросы по опыту и фреймворкам — как вы строили API на FastAPI, почему выбрали именно такую схему в SQLAlchemy, как ловили утечку памяти в проде.

Чем выше грейд, тем меньше «расскажите определение» и больше «почему так сделано» и «какой trade-off вы приняли». Разберём типичные блоки.

GIL и конкурентность

  • Что такое GIL и зачем он нужен? Global Interpreter Lock — мьютекс, позволяющий выполнять байткод только одному потоку за раз в рамках процесса. Нужен для упрощения управления памятью (потокобезопасный рефкаунтинг) и совместимости C-расширений.
  • threading vs multiprocessing vs asyncio — когда что? threading хорош для I/O-bound задач (GIL отпускается на I/O), multiprocessing — для CPU-bound (обходит GIL через отдельные процессы), asyncio — для большого числа I/O-операций в одном потоке без накладных расходов на потоки.
  • Что изменилось с free-threaded CPython? В Python 3.13 появилась экспериментальная сборка без GIL (PEP 703, флаг --disable-gil). Это отдельный билд, не дефолтный; в 3.13 он официально experimental. Ждут понимания, что no-GIL — про настоящий параллелизм потоков на CPU, но пока с оговорками по стабильности и производительности однопоточного кода.
  • Отпускается ли GIL при сетевом запросе? Да — на блокирующих системных вызовах (I/O, time.sleep) поток освобождает GIL, поэтому потоки реально полезны для I/O-bound нагрузки.
  • Почему multiprocessing дороже потоков? Отдельные процессы не делят память, данные передаются через сериализацию (pickle), есть стоимость на старт процесса и IPC.

Генераторы и итераторы

  • Чем итератор отличается от итерируемого? Iterable реализует __iter__, итератор дополнительно __next__ и хранит состояние перебора. for под капотом вызывает iter(), затем next() до StopIteration.
  • Как работает yield? Превращает функцию в генератор: вызов возвращает объект-генератор, тело выполняется лениво, состояние замораживается между next(). Ждут слова «ленивость» и «состояние сохраняется».
  • Generator vs list comprehension — когда что? Генератор не материализует все элементы, экономит память на больших или бесконечных потоках; список — когда нужен повторный проход или индексация.
  • Что делают yield from и .send()? yield from делегирует итерацию вложенному генератору, .send(value) передаёт значение обратно в точку yield — основа корутин до asyncio.
  • Можно ли пройти генератор дважды? Нет, он одноразовый — после исчерпания снова отдаёт StopIteration. Частая ловушка в коде.

Декораторы и замыкания

  • Что такое замыкание? Функция, захватывающая переменные из охватывающей области; они живут, пока жива вложенная функция. Изменение внешней переменной — через nonlocal.
  • Как устроен декоратор? Функция, принимающая функцию и возвращающая обёртку. @decorator — синтаксический сахар для f = decorator(f).
  • Зачем functools.wraps? Сохраняет метаданные оборачиваемой функции (__name__, __doc__, сигнатуру), иначе они подменяются обёрткой — ломает интроспекцию и документацию.
  • Как написать декоратор с аргументами? Дополнительный уровень вложенности: фабрика принимает аргументы и возвращает сам декоратор.
  • Чем lru_cache помогает и где опасен? Кэширует результаты по аргументам; опасен на изменяемых данных и потенциальной утечкой памяти при maxsize=None на горячем пути.

ООП: MRO, dunder-методы, модели данных

  • Как работает MRO? Method Resolution Order вычисляется алгоритмом C3-линеаризации; порядок виден в Cls.__mro__. Решает diamond-проблему при множественном наследовании.
  • Зачем super() и как он использует MRO? super() идёт по цепочке MRO, а не «к родителю», — поэтому в кооперативном наследовании важно вызывать super().__init__() везде.
  • Какие dunder-методы стоит знать? __init__/__new__, __eq__/__hash__ (вместе), __repr__/__str__, __enter__/__exit__ для контекст-менеджеров, __getitem__/__iter__ для контейнеров.
  • dataclass vs attrs vs pydantic — в чём разница? dataclass — встроенный, генерирует boilerplate, без валидации. attrs — мощнее и быстрее, с валидаторами и конвертерами. pydantic — валидация и парсинг данных по типам в рантайме, основа FastAPI. Ждут «pydantic валидирует, dataclass — нет».
  • Что делает __slots__? Запрещает динамический __dict__, фиксирует набор атрибутов — экономит память на множестве объектов и чуть ускоряет доступ.

Типизация

  • Что дают type hints в рантайме? По умолчанию ничего — это аннотации для статических анализаторов (mypy, pyright) и IDE; CPython их не проверяет. Ждут понимания, что типы не enforced без сторонних инструментов.
  • Что такое Protocol? Структурная типизация (duck typing на уровне типов): класс соответствует протоколу, если реализует нужные методы, без явного наследования.
  • Optional[X] vs X | None? Эквивалентны; синтаксис X | None доступен с Python 3.10 и считается предпочтительным.
  • Зачем TypeVar/дженерики и что нового в 3.12? Для типобезопасных контейнеров и функций. В Python 3.12 появился новый синтаксис дженериков (PEP 695): def first[T](x: list[T]) -> T без явного TypeVar.
  • mypy strict — что ловит? Запрещает неявный Any, требует аннотаций, ловит несоответствия — ждут, что вы хоть раз гоняли строгий режим в CI.

Память и производительность

  • Как устроено управление памятью? Основной механизм — подсчёт ссылок (reference counting): объект удаляется, когда счётчик ссылок падает до нуля. Поверх — циклический сборщик мусора, который ловит ссылочные циклы, недоступные рефкаунтингу.
  • Зачем нужен циклический GC, если есть рефкаунтинг? Рефкаунтинг не разрывает циклы (a.b = b; b.a = a) — такие объекты собирает поколенческий GC (gc модуль).
  • Как искать утечки памяти? tracemalloc, objgraph, рост gc.get_objects(); типичные причины — глобальные кэши, незакрытые ссылки, замыкания.
  • Что даёт __slots__ для памяти? Убирает per-instance __dict__ — заметная экономия при миллионах мелких объектов.
  • Почему «преждевременная оптимизация — зло» здесь уместна? Ждут, что вы сначала профилируете (cProfile, py-spy), а не угадываете узкое место.

asyncio

  • Что такое event loop? Цикл, который выполняет корутины и колбэки в одном потоке, переключаясь на точках await, когда операция ждёт I/O. Параллелизма по CPU не даёт — это конкурентность, не параллелизм.
  • Чем корутина отличается от Task? Корутина — объект из async def, ничего не делает, пока её не запустят. Task оборачивает корутину и планирует её выполнение в loop (asyncio.create_task).
  • Что значит await? Уступает управление event loop до готовности awaitable; забыть await — частая ошибка, корутина просто не выполнится.
  • Типичные гочи asyncio? Блокирующий вызов (requests, тяжёлый CPU, time.sleep) внутри корутины замораживает весь loop; для блокирующего кода — run_in_executor. Ещё — смешивание sync и async библиотек.
  • asyncio.gather vs TaskGroup? gather запускает корутины конкурентно и собирает результаты; TaskGroup (Python 3.11) даёт структурированную конкурентность с корректной отменой при ошибке.

Вопросы по экосистеме

Без глубокого погружения, но проверяют осознанность выбора:

  • FastAPI vs Django — когда что? FastAPI — async-first, лёгкий, на pydantic, для API и микросервисов. Django — батарейки в комплекте (ORM, админка, auth), для монолитов с богатой доменной логикой.
  • Зачем FastAPI зависит от pydantic? Валидация и сериализация request/response по type hints — автоматически, с генерацией OpenAPI-схемы.
  • SQLAlchemy: что такое сессия и identity map? Сессия — unit of work, отслеживает изменения; identity map гарантирует один объект на строку в рамках сессии. Ждут понимания lazy vs eager loading и проблемы N+1.
  • Как избежать N+1 в SQLAlchemy? Eager loading через selectinload/joinedload вместо ленивой подгрузки в цикле.

Чего ждут от middle vs senior

Middle должен уверенно отвечать «как это работает» и «когда использовать»: объяснить GIL, написать декоратор, выбрать между списком и генератором, не запутаться в asyncio на базовом уровне. Достаточно знания механизмов и здравого выбора инструментов.

Senior отвечает на «почему так в CPython» и «какой trade-off вы выбрали в проде». Здесь ждут историй: как вы диагностировали утечку памяти, почему отказались от потоков в пользу процессов, как структурировали async-сервис под нагрузку, какие грабли поймали. Senior умеет сказать «зависит от» и обосновать — а не выдать заученное определение.

Как готовиться

Сначала прогоните темы списком: по каждому блоку выше попробуйте вслух объяснить вопрос так, будто перед вами интервьюер. Места, где «вроде знаю, но сформулировать не могу», — ваши слабые точки. Параллельно тренируйте лайвкодинг на структурах данных и небольших практических задачах, проговаривая ход мысли.

Хорошо работает связка с LLM: попросите модель сыграть интервьюера и гонять вас по темам — подробный разбор такого подхода есть в гайде про подготовку к собеседованию с LLM. Но AI хвалит охотнее, чем стоит, и не передаёт давление живого диалога. Поэтому за несколько дней до реального интервью возьмите мок-собеседование с практикующим senior-инженером — он подсветит дыры, которые вы сами не замечаете, и потренирует отвечать под напряжением.

В IT-ХОЗЯЕВА мок-собеседования и доступ к базе практикующих менторов входят в тариф ХОЗЯИН за 1000 ₽/мес — можно прогнать Python-секцию с инженером по вашему стеку, получить разбор резюме и наметить план подготовки. Это удобный способ соединить самостоятельную теорию с живой обратной связью, не собирая контакты менторов по знакомым.

Главное — не заучивать ответы. Интервьюер слышит шаблон за секунду. Понимайте механизмы, держите наготове примеры из своей практики, и тогда даже неожиданный вопрос превратится в разговор, а не в провал.