Вопросы на собеседовании Python junior чаще проверяют не определения, а способность предсказать поведение кода, назвать граничный случай и предложить проверку. Подготовьте типы и mutability, списки и словари, функции, области видимости, исключения, итераторы, классы, тесты, HTTP и SQL, а каждую тему объясните на коротком примере. Связывайте ответ с версией языка и контрактом задачи.
Формат зависит от вакансии. Backend-команда добавит HTTP, framework, базу данных и асинхронность, аналитическая роль спросит про файлы, pandas и качество данных, автоматизация тестирования добавит pytest и API. Python tutorial охватывает структуры данных, функции, модули, исключения, классы и итераторы. Используйте его как карту, а требования конкретной вакансии как приоритет.
Типы, ссылки, функции, исключения и протоколы объектов.
Одна задача с тестами и оценкой сложности.
Архитектурное решение, ошибка и личный вклад.

Вопросы на собеседовании Python junior с примером ловушки
Классическая тема связана с изменяемым аргументом по умолчанию. Значение по умолчанию вычисляется при определении функции, поэтому один список переиспользуется между вызовами. Хороший ответ не заканчивается словом mutable: покажите результат, исправьте код и объясните, когда создаётся новый объект.
def add_tag(tag, tags=None):
# Создаём новый список для каждого вызова без переданного значения
if tags is None:
tags = []
tags.append(tag)
return tags
first = add_tag("python")
second = add_tag("junior")
print(first) # ['python']
print(second) # ['junior']- Вызовы не разделяют один изменяемый список
- Кандидат объясняет разницу между None и готовым [] в сигнатуре
Следом интервьюер может спросить, почему проверка написана через is None, а не == None. Оператор is сравнивает идентичность объектов, и None является singleton. Затем добавьте тест, где список передан явно: функция должна изменить именно его или, если контракт требует неизменности, создать копию. Важно сначала назвать контракт, а не угадывать желаемое поведение.
25 тем, собранных в пять блоков
| Элемент | Что означает | Что делать |
|---|---|---|
| База языка | Типы, mutability, is и ==, truthiness, scope | Предсказать вывод |
| Коллекции | list, tuple, dict, set, comprehension | Выбрать структуру |
| Функции | args, kwargs, closure, decorator, generator | Объяснить выполнение |
| Надёжность | exceptions, context manager, tests, logging | Обработать сбой |
| Приложение | HTTP, JSON, SQL, Git, проект | Проследить данные |
Для словаря повторите хешируемость ключей и среднюю стоимость операций, но не обещайте точную сложность без условий. Для генератора объясните ленивое получение значений и однократный проход. Для исключений различайте ожидаемую ошибку пользователя и программный дефект. Для контекстного менеджера покажите обязательное освобождение ресурса. Для SQL повторите JOIN, GROUP BY, NULL и параметры запросов.

Практика: разберите ловушку Python с изменяемым default
Соберите файл tags.py и доведите ловушку с изменяемым значением по умолчанию до наблюдаемого вывода. Успех: первая версия функции накапливает теги между вызовами, исправленная через None возвращает новый список каждый раз. Разницу зафиксируйте выводом print и одним тестом pytest, чтобы на собеседовании показывать код, а не пересказ.
- Плохая версия add_tag. Напишите def add_tag(tag, tags=[]) с append и return, вызовите её с 'python', потом с 'junior' и напечатайте оба результата. В консоли появятся ['python'] и ['python', 'junior']: список один на все вызовы.
- id списка по умолчанию. Напечатайте id возвращённого списка после каждого вызова и заодно add_tag.__defaults__. Идентификаторы совпадут, а в __defaults__ будет виден тот самый растущий список, созданный один раз при определении функции.
- Починка через None. Поменяйте сигнатуру на def add_tag(tag, tags=None) и добавьте внутри if tags is None: tags = []. Повторный запуск напечатает ['python'] и ['junior']: каждый вызов получает свой список.
- Явно переданный список. Вызовите add_tag('dev', my_tags) с готовым списком и проверьте, что изменился именно my_tags. Если контракт требует не трогать вход, возвращайте tags + [tag] или работайте с копией list(tags).
- Тест в pytest. Напишите test_add_tag_isolated с двумя проверками подряд: assert add_tag('a') == ['a'] и assert add_tag('b') == ['b']. На версии с None тест зелёный, на версии со списком в сигнатуре падает второй assert.
Верните в сигнатуру tags=[] и запустите pytest ещё раз. Второй assert упадёт с сообщением вида assert ['a', 'b'] == ['b'], потому что список из сигнатуры создан один раз при определении функции и живёт между вызовами. Тот же эффект повторите на словаре: def add_option(key, options={}) накопит ключи ровно так же, и это удобно показать интервьюеру как обобщение.
Разберите тем же способом соседние ловушки: замыкание в цикле for с lambda, срез списка против copy и попытка положить список ключом словаря. Затем перенесите приём в задачу с вакансии: опишите контракт функции одной строкой в docstring и закройте его двумя тестами, на обычный вход и на пустой. Такой файл открывают на собеседовании и объясняют решение прямо по коду.
Частые ошибки и почему они появляются
Заученный список вопросов создаёт ложное чувство готовности. Небольшое изменение примера разрушает ответ, если кандидат не запускал код. Вторая ошибка: спорить о стиле до уточнения требований. Третья: описывать командный проект так, будто весь код написан лично. Гораздо сильнее честно назвать собственный модуль, решение и исправленный дефект.
Добавьте пример, наблюдаемый результат и границу.
Скажите, что известно, сформулируйте гипотезу и способ проверить.
Уточните версию Python, формат входа и ожидаемое поведение.
Самопроверка
Почему пустой список опасен как значение по умолчанию?
Список в сигнатуре создаётся один раз при определении функции, поэтому все вызовы без явного аргумента работают с одним объектом и накапливают в нём данные. Пишите tags=None и создавайте новый список внутри функции.
Чем is отличается от == в Python?
Оператор is сравнивает идентичность: слева и справа должен быть один и тот же объект в памяти. Оператор == вызывает __eq__ и сравнивает значения, поэтому два одинаковых по содержимому списка дают True для == и False для is.
Почему проверяют is None, а не == None?
None существует в единственном экземпляре, поэтому проверка на идентичность через is None точна и не зависит от чужой реализации __eq__. Класс может переопределить == и вернуть True при сравнении с None, а обмануть is так не получится.
Какие объекты можно использовать ключом словаря?
Ключом словаря может быть только хешируемый объект: число, строка, кортеж из хешируемых элементов, экземпляр класса с корректным __hash__. Список и словарь ключами быть не могут, потому что они изменяемы и хеш перестал бы соответствовать содержимому.
Чем генератор отличается от списка?
Генератор отдаёт значения по одному по мере запроса и не держит всю последовательность в памяти, а список создаётся целиком сразу. Пройти по генератору можно один раз: после исчерпания он не начинается заново, и длину у него не спросить.
Что рассказывать про командный проект на собеседовании?
Про командный проект называйте свой участок: какую задачу вы взяли, какое решение выбрали, как проверили и какой дефект исправили. Присвоение чужого кода вскрывается первым же уточняющим вопросом про детали реализации.
Что делать дальше
Запишите ответы на 25 тем голосом и для пяти из них создайте запускаемые примеры с тестами. Системную практику даёт курс Python-разработчика. Алгоритмы закрепите по статье про задачи на Python, а критерии готовности сравните с планом до junior.
