Собеседование Python-разработчика охватывает внутренности языка, асинхронность, Django или FastAPI и работу с базой. Ниже — самые частые вопросы с эталонными ответами. Senior: архитектуру, трейд-оффы, менторство и принятие решений.
1
Объясните разницу между генератором и обычной функцией. Зачем нужен yield?
Ответ
Обычная функция вычисляет всё и возвращает один раз; генератор приостанавливается на каждом yield и возобновляется с того же места, отдавая значения лениво. Это значит постоянный расход памяти независимо от количества элементов, поэтому можно итерироваться по файлу в гигабайты или по бесконечной последовательности. Именно yield превращает функцию в конечный автомат, который интерпретатор умеет ставить на паузу.
2
Что такое *args и **kwargs? Приведите пример использования.
Ответ
*args собирает лишние позиционные аргументы в кортеж, **kwargs собирает лишние именованные в словарь. Их применяют, когда функция должна принимать произвольную сигнатуру — чаще всего в декораторах и обёртках, пробрасывающих всё дальше. Зеркальное применение — распаковка: вызов f(*items, **options) разворачивает последовательность и словарь в аргументы.
3
В чём разница между multiprocessing, threading и asyncio?
Ответ
Threading даёт конкурентность внутри одного процесса и помогает только на I/O из-за GIL. Multiprocessing поднимает отдельные интерпретаторы с настоящим параллелизмом ценой запуска процессов и межпроцессного обмена — это правильный выбор для CPU-нагрузки. asyncio это однопоточная кооперативная конкурентность: задачи уступают управление в точках await, что масштабируется на десятки тысяч сокетов, но блокирует всё, если внутри корутины вызвать синхронный код.
4
Что такое контекстный менеджер? Как реализовать свой?
Ответ
Контекстный менеджер гарантирует подготовку и завершение вокруг блока — именно это использует with, чтобы закрыть файл или отпустить блокировку даже при исключении. Реализовать можно классом с __enter__ и __exit__ либо генератором под декоратором @contextlib.contextmanager, который делает один yield между кодом подготовки и очистки. Метод __exit__ получает информацию об исключении и может подавить его, вернув True.
5
Объясните MRO и множественное наследование.
Ответ
Method Resolution Order задаёт порядок, в котором Python ищет атрибут по классам, и вычисляется алгоритмом линеаризации C3. Он гарантирует, что класс всегда идёт раньше своих родителей и что порядок базовых классов соблюдается, благодаря чему ромбовидное наследование ведёт себя предсказуемо. super() идёт по MRO, а не прыгает сразу к родителю, поэтому кооперативное множественное наследование требует, чтобы каждый класс в цепочке вызывал super().
6
Что такое N+1 в Django ORM? Как помогают select_related и prefetch_related?
Ответ
N+1 возникает, когда queryset возвращает N объектов, и каждое обращение к связанному полю порождает отдельный запрос. select_related решает это для ForeignKey и OneToOne, делая SQL JOIN и заполняя связанный объект тем же запросом. prefetch_related работает с ManyToMany и обратными связями: выполняет второй запрос и соединяет результаты уже в Python, поэтому запросов получается два, а не один.
7
В чём разница между shallow copy и deep copy?
Ответ
Поверхностная копия создаёт новый внешний контейнер, но сохраняет ссылки на те же вложенные объекты, поэтому изменение вложенного списка видно через обе копии. Глубокая копия рекурсивно дублирует всё и даёт полную независимость ценой времени и памяти. На практике из этого рождается баг с изменяемым значением по умолчанию или общим вложенным конфигом, который один вызывающий меняет для всех.
8
В чём разница между __str__ и __repr__?
Ответ
__repr__ адресован разработчику и в идеале должен быть однозначным — часто это выражение, которым объект можно было бы воссоздать; именно его показывают REPL и отладчики. __str__ адресован конечному пользователю, его вызывают print() и str(), а при отсутствии он падает обратно на __repr__. Привычка реализовывать __repr__ ценнее, потому что она делает читаемыми логи и трейсбеки.
9
Как Python управляет памятью и что такое подсчёт ссылок?
Ответ
CPython освобождает объект сразу, как только счётчик ссылок падает до нуля, поэтому освобождение немедленное и предсказуемое. Так как одним подсчётом ссылок нельзя убрать циклические ссылки, периодически запускается поколенческий циклический сборщик, который их находит и собирает. Практические следствия: явно закрывать ресурсы всё равно нужно, а типичная причина утечки памяти — ссылка, застрявшая в кеше или замыкании.
🦎
Прочитать ответы недостаточно
На собеседовании ты говоришь вслух под давлением. Кем задаст эти же вопросы, оценит каждый ответ и покажет, что именно подтянуть.
Пройти интервью Senior Python Backend →Бесплатно · 3 интервью в месяц