Подготовка к Python backend интервью

Вопросы и ответы на Python собеседовании 2026

Сфокусированная подборка вопросов для Python backend интервью. Используйте каждый ответ как структуру устного ответа: концепт, пример и компромиссы.

Начать Python mock interview на русскомКредитная карта не требуется. Доступна 1 бесплатная сессия.
Практика технических собеседований на английскомРежим, в котором не носители языка могут потренироваться проходить интервью.

База и модель данных Python

1Какие встроенные типы данных есть в Python и какие из них изменяемые?

В Python есть скалярные типы NoneType, bool, int, float и complex; текстовые и бинарные типы str, bytes и bytearray; последовательности list, tuple и range; коллекции dict, set и frozenset. Ключевое различие для собеседования — mutability: list, dict, set и bytearray меняются на месте, а числа, bool, str, bytes, tuple, range, frozenset и None неизменяемы. Важный нюанс: сам tuple всегда хранит фиксированный набор ссылок, но внутреннее состояние изменяемого объекта по такой ссылке может меняться.

Попробовать ответить на вопрос AI-тренеру

2Чем list, tuple, set и dict отличаются в реальном коде?

list — упорядоченная изменяемая последовательность, удобная для накопления результатов и данных, которые меняются. tuple — упорядоченная неизменяемая структура для фиксированных записей и возврата нескольких значений. set хранит уникальные hashable-объекты и подходит для membership checks и deduplication. dict отображает hashable-ключи в значения и обычно используется для индексов, lookup и JSON-подобных данных. В современных версиях dict сохраняет порядок вставки, но его главная роль — доступ по ключу.

items = ["a", "b", "a"]
unique = set(items)
index = {"user_id": 42}
point = (10, 20)
Попробовать ответить на вопрос AI-тренеру

3Чем is отличается от ==?

== проверяет равенство по значению, обычно через __eq__. is проверяет идентичность: две ссылки указывают на один и тот же объект. В production-коде is обычно используют для singleton-проверок, например value is None, или для специальных sentinel-объектов. Нельзя полагаться на кеширование маленьких чисел или interning строк: в маленьких примерах is может случайно сработать, но семантически это неправильная проверка.

value = None

if value is None:
    print("missing")
Попробовать ответить на вопрос AI-тренеру

4Что такое hashable-объект и почему это важно?

Hashable-объект имеет стабильный hash на протяжении жизни и равенство, согласованное с этим hash. Это важно, потому что ключи dict и элементы set зависят от hash. Большинство неизменяемых built-ins hashable, но неизменяемый контейнер не делает вложенные объекты hashable автоматически: tuple со списком внутри не hashable. Если объект используется как ключ, поля, участвующие в __eq__ или __hash__, не должны меняться после вставки, иначе объект может потеряться в dict или set.

Попробовать ответить на вопрос AI-тренеру

5Как работают срезы, отрицательные индексы и шаг?

Срез sequence[start:stop:step] включает start, исключает stop и движется с шагом step. Пропущенные границы выбираются в зависимости от направления шага. Отрицательные индексы считаются с конца, поэтому s[-1] — последний элемент. Отрицательный step идет справа налево, а s[::-1] возвращает перевернутую последовательность. Нужно помнить, что срез часто создает новый объект, поэтому он выразительный, но не бесплатный на больших данных.

text = "interview"

print(text[1:5])
print(text[::-1])
Попробовать ответить на вопрос AI-тренеру

Функции и области видимости

6Как Python передает аргументы в функции?

Python передает ссылки на объекты через присваивание; это часто называют call by sharing. Параметры функции становятся локальными именами, связанными с теми же объектами, которые передал вызывающий код. Если объект изменяемый, функция может изменить его, и вызывающий код это увидит. Если функция просто присвоит параметру другое значение, изменится только локальная привязка. Хороший ответ различает mutation in place и rebinding: items.append(...) или items.clear() меняет список у вызывающего кода, а items = [] внутри функции только переназначает локальное имя.

def add_item(items):
    items.append("new")

def replace_items(items):
    items = []

values = []
add_item(values)
replace_items(values)

print(values)  # ["new"]
Попробовать ответить на вопрос AI-тренеру

7Почему изменяемые аргументы по умолчанию опасны?

Значения по умолчанию вычисляются один раз при определении функции, а не при каждом вызове. Поэтому list или dict в default может разделяться между всеми вызовами и случайно хранить состояние. Безопасный паттерн: def f(items=None), затем внутри создать новый список, если items is None. Иногда общее состояние нужно специально, например для маленького cache, но тогда это должно быть явно и понятно читателю.

def add_tag(tag, tags=[]):
    tags.append(tag)
    return tags

print(add_tag("python"))
print(add_tag("backend"))  # Same list reused

def safe_add_tag(tag, tags=None):
    tags = [] if tags is None else tags
    tags.append(tag)
    return tags
Попробовать ответить на вопрос AI-тренеру

8Для чего нужны *args и **kwargs?

*args собирает лишние позиционные аргументы в tuple, а **kwargs собирает лишние именованные аргументы в dict. Они полезны для wrappers, decorators, гибких API и проброса вызовов дальше. При вызове *iterable распаковывает позиционные значения, а **mapping — keyword values. Компромисс в читаемости: явные параметры лучше для стабильного публичного API, а args/kwargs лучше на границах совместимости и forwarding.

def call_api(path, *args, **kwargs):
    print(path, args, kwargs)

call_api("/users", 1, 2, timeout=5)

values = [1, 2]
options = {"timeout": 5}
call_api("/users", *values, **options)
Попробовать ответить на вопрос AI-тренеру

9Как Python ищет имена по правилу LEGB?

Python ищет имя в Local, Enclosing, Global и Builtins. Чтение имени идет по этому порядку. Присваивание внутри функции обычно создает локальную переменную, поэтому можно получить UnboundLocalError, если прочитать имя до локального присваивания. global направляет присваивание в модульную область, nonlocal — во внешнюю функцию. В production-коде их лучше использовать редко, потому что они усложняют поток состояния.

total = 0

def add(value):
    global total
    total += value

def counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment
Попробовать ответить на вопрос AI-тренеру

10Что такое closure и late binding?

Closure — функция, которая сохраняет доступ к переменным из внешней области после завершения внешней функции. Это полезно для decorators, callback factories и функций с конфигурацией. Late binding означает, что свободная переменная ищется при вызове внутренней функции, а не при ее создании. Поэтому lambda в цикле может увидеть последнее значение счетчика. Значение фиксируют через default argument, например lambda i=i: i, или через отдельную factory-функцию.

callbacks = []

for i in range(3):
    callbacks.append(lambda: i)

print([callback() for callback in callbacks])  # [2, 2, 2]

callbacks = []
for i in range(3):
    callbacks.append(lambda i=i: i)

print([callback() for callback in callbacks])  # [0, 1, 2]
Попробовать ответить на вопрос AI-тренеру

ООП, итерация и ресурсы

11Чем переменная класса отличается от переменной экземпляра?

Переменная класса хранится на объекте класса и разделяется экземплярами, пока экземпляр не перекроет ее собственным атрибутом. Переменная экземпляра хранится на конкретном объекте и обычно задается как self.name в __init__. Неизменяемые class constants обычно безопасны, но изменяемые class attributes часто становятся багом, если их случайно используют как состояние экземпляра. В ответе полезно упомянуть порядок поиска: сначала instance, потом class и ancestors.

class Cart:
    items = []

first = Cart()
second = Cart()

first.items.append("book")
print(second.items)  # ["book"]

class SafeCart:
    def __init__(self):
        self.items = []
Попробовать ответить на вопрос AI-тренеру

12Как работают inheritance, MRO и super()?

Python ищет атрибуты по Method Resolution Order, который можно посмотреть через ClassName.__mro__. В одиночном наследовании все просто, но при множественном наследовании Python использует C3 linearization, чтобы получить согласованный порядок. super() означает не просто 'вызвать родителя', а 'вызвать следующую реализацию в MRO'. Это позволяет cooperative multiple inheritance, если методы принимают совместимые аргументы и каждый класс корректно вызывает super().

class A:
    def save(self):
        print("A")

class B(A):
    def save(self):
        print("B")
        super().save()

class C(A):
    def save(self):
        print("C")
        super().save()

class D(B, C):
    pass

D().save()  # B, C, A
Попробовать ответить на вопрос AI-тренеру

13Чем отличаются iterable, iterator и generator?

Iterable — объект, который возвращает iterator через iter(), например list или file object. Iterator хранит состояние обхода, реализует __next__ и вызывает StopIteration при завершении. Generator — удобный способ создать iterator через yield или generator expression. Генераторы экономят память, потому что лениво производят значения, но обычно одноразовые и не поддерживают индексацию как list.

def read_lines(path):
    with open(path, encoding="utf-8") as file:
        for line in file:
            yield line.strip()
Попробовать ответить на вопрос AI-тренеру

14Что такое context manager и зачем нужен with?

Context manager задает поведение входа и выхода через __enter__ и __exit__, либо создается через contextlib.contextmanager. with делает управление ресурсами явным и надежным: файлы закрываются, lock освобождается, транзакция commit/rollback выполняется даже при исключениях. __exit__ получает информацию об исключении и может подавить его, вернув true, но подавлять ошибки стоит осторожно.

from contextlib import contextmanager

with open("data.txt", encoding="utf-8") as file:
    data = file.read()

@contextmanager
def temporary_setting():
    print("enter")
    try:
        yield
    finally:
        print("exit")
Попробовать ответить на вопрос AI-тренеру

15Чем shallow copy отличается от deep copy?

Shallow copy создает новый внешний контейнер, но оставляет ссылки на те же вложенные объекты. Deep copy рекурсивно копирует вложенные объекты, где это возможно. Для простых плоских списков shallow copy часто достаточно. Для вложенных изменяемых структур shallow copy может разделять состояние и удивлять. Deep copy дороже и может упасть с TypeError или PicklingError для ресурсов: открытых файлов, sockets, database sessions или объектов с важной identity-семантикой.

from copy import copy, deepcopy

original = [[1], [2]]
shallow = copy(original)
deep = deepcopy(original)

original[0].append(99)

print(shallow)  # [[1, 99], [2]]
print(deep)     # [[1], [2]]
Попробовать ответить на вопрос AI-тренеру

Runtime, async и production-код

16Что такое GIL и как он влияет на backend-код?

В стандартном CPython Global Interpreter Lock позволяет только одному потоку выполнять Python bytecode в конкретный момент. Поэтому threads обычно не ускоряют CPU-bound Python-код. Но threads полезны для I/O-bound задач, потому что GIL освобождается во время многих операций ожидания. Для CPU-heavy работы используют multiprocessing, native extensions, vectorized native libraries или отдельные сервисы. Для интервью в 2026 году важно упомянуть Python 3.13+ free-threaded CPython builds: GIL становится опциональным для совместимого кода, но зависимости и performance нужно проверять.

Попробовать ответить на вопрос AI-тренеру

17Когда выбирать threads, processes или asyncio?

Threads подходят для blocking I/O и библиотек только с синхронным API. Processes выбирают для CPU-bound работы, изоляции или устойчивости к падениям, принимая overhead сериализации и памяти. asyncio подходит для большого числа concurrent I/O operations с async-compatible библиотеками: async database drivers, HTTP clients, queues. Практический выбор зависит от framework и dependencies: async endpoint с blocking calls может стать хуже, а не лучше.

Попробовать ответить на вопрос AI-тренеру

18Для чего async/await полезны в Python web services?

async и await дают cooperative concurrency. Coroutine возвращает управление event loop, когда ожидает I/O, и в это время могут выполняться другие задачи. Это полезно для API, которые ждут database, HTTP calls, queues или sockets. Это не ускоряет CPU-bound код: тяжелые вычисления блокируют event loop, если не вынести их в worker, process или native code. В FastAPI обычный def endpoint выполняется в thread pool, а blocking calls внутри async def могут заблокировать event loop; async помогает только когда call path использует non-blocking async I/O.

import asyncio

async def load_user():
    await asyncio.sleep(0.1)
    return {"id": 1}

async def main():
    user, settings = await asyncio.gather(
        load_user(),
        load_user(),
    )
    return user, settings
Попробовать ответить на вопрос AI-тренеру

19Как правильно обрабатывать exceptions в production Python?

Перехватывайте самый конкретный exception, который можете обработать, и делайте это на слое, который может восстановиться, добавить контекст или перевести ошибку в domain error. Избегайте bare except и молчаливого swallowing: это скрывает потерю данных и operational problems. Используйте raise для повторного возбуждения и raise NewError(...) from exc для сохранения причины. На границах системы нужны полезные logs, корректные HTTP errors и сообщения без утечки secrets.

try:
    result = parse_payload(payload)
except ValueError as exc:
    raise InvalidRequest("Invalid payload") from exc
Попробовать ответить на вопрос AI-тренеру

20Как структурировать и тестировать production Python service?

Отделяйте domain logic от framework и infrastructure code, чтобы основное поведение тестировалось без сервера и базы. Используйте configuration из environment или typed settings, logging вместо print, dependency injection на границах и явные timeouts для network calls. В тестах сочетайте unit tests для чистой логики, integration tests для database/external boundaries и несколько end-to-end checks для критических flows. Mock используйте на понятных границах, а проверяйте observable behavior, не private implementation details.

Попробовать ответить на вопрос AI-тренеру