Перейти к содержанию

Python: задачи лайвкодинг

~3 минуты чтения

Предварительно: Подготовка к Python-интервью | Gotchas и трики

Лайвкодинг -- самый стрессовый этап Python-интервью: 45-60 минут, shared editor (CoderPad, HackerRank), интервьюер смотрит в реальном времени. По данным Glassdoor, декораторы спрашивают в 35% Python-собеседований (Squarespace, Яндекс, Minted), генераторы -- в 25% (Morgan Stanley, Airbnb, Hudson River Trading), async -- в 15% (Riot Games, FAANG). Ниже -- реальные задачи от 20+ компаний с шаблонами решений.


DECORATORS

Squarespace

# Напишите декоратор мемоизации для функции сложения
def memoize(func):
    # TODO: реализовать кеширование результатов
    pass

@memoize
def add(a: int, b: int) -> int:
    return a + b

add(2, 3)  # вычисляет
add(2, 3)  # должен вернуть из кеша

Minted

# Throttle декоратор — функция выполняется только если прошло >100ms
def throttle(min_interval_ms: int = 100):
    # TODO: реализовать ограничение частоты вызовов
    pass

@throttle(min_interval_ms=100)
def print_message():
    print("Hello!")

print_message()  # выполнится
print_message()  # пропустит (слишком быстро)
time.sleep(0.2)
print_message()  # выполнится

Squarepoint Capital

# Декоратор с полной типизацией (CoderPad live coding)
from typing import Callable, TypeVar, ParamSpec

P = ParamSpec('P')
R = TypeVar('R')

def logged(func: Callable[P, R]) -> Callable[P, R]:
    # TODO: реализовать логирование вызовов с сохранением типов
    pass

Яндекс

# Параметризированный декоратор замера времени
def timing(unit: str = "seconds"):
    # TODO: реализовать замер времени
    # unit может быть "seconds" или "milliseconds"
    pass

@timing(unit="milliseconds")
def slow_function():
    time.sleep(1)

# Ожидаемый вывод: slow_function took 1000.50ms

Habr (Русские IT-компании)

# 1. Retry с exponential backoff
def retry(max_tries: int = 3, delay: float = 1, backoff: int = 2):
    # TODO: повторять вызов при ошибке с увеличивающейся задержкой
    pass

@retry(max_tries=3, delay=1, backoff=2)
def unstable_api():
    if random.random() < 0.7:
        raise ConnectionError()
    return "OK"

# 2. Rate limiter
def rate_limit(calls: int, period: int):
    # TODO: ограничить количество вызовов за период
    pass

@rate_limit(calls=10, period=60)  # макс 10 вызовов в минуту
def api_call():
    pass

GENERATORS

Hudson River Trading

# "Build a Python generator" — CoderPad, 3 часа
# Конкретная задача не раскрыта, формат: online live coding

Morgan Stanley

# Fibonacci через generator
def fibonacci(n: int):
    # TODO: yield первые n чисел Фибоначчи
    pass

list(fibonacci(10))  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Airbnb

# Flatten вложенного списка любой глубины
def flatten(lst):
    # TODO: рекурсивно yield все элементы
    pass

list(flatten([1, [2, [3, 4]], 5]))  # [1, 2, 3, 4, 5]

Stripe / Google / Amazon

# Обработка большого файла батчами (без загрузки в память)
def read_batches(filename: str, batch_size: int = 1000):
    # TODO: yield батчи по batch_size строк
    pass

for batch in read_batches("huge.txt", 1000):
    process(batch)

COMPREHENSIONS

J.P. Morgan

# Генерация степеней: num^1, num^2, num^3 для чисел 1-4
powers = ...  # TODO: list comprehension

# Ожидаемый результат: [1, 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64]

Jump Trading

# Транспонирование матрицы через comprehension
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = ...  # TODO: nested list comprehension

# Ожидаемый результат: [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Goldman Sachs

# Flatten вложенного списка
nested = [[1, 2], [3, 4], [5]]
flat = ...  # TODO: list comprehension
# Ожидаемый результат: [1, 2, 3, 4, 5]

# Dict из двух списков
keys, values = ['a', 'b', 'c'], [1, 2, 3]
d = ...  # TODO: dict comprehension
# Ожидаемый результат: {'a': 1, 'b': 2, 'c': 3}

Bloomberg

# Группировка по ключу
data = [
    {'name': 'Alice', 'dept': 'IT'},
    {'name': 'Bob', 'dept': 'IT'},
    {'name': 'Charlie', 'dept': 'HR'}
]
by_dept = ...  # TODO: dict comprehension с группировкой

# Ожидаемый результат: {'IT': ['Alice', 'Bob'], 'HR': ['Charlie']}

Tinkoff

# Трансформация вложенных словарей (lowercase ключи)
params = {
    'device1': {'Name': 'Sensor', 'Value': '123'},
    'device2': {'Name': 'Motor', 'Value': '456'}
}
result = ...  # TODO: nested dict comprehension

# Ожидаемый результат:
# {'device1': {'name': 'Sensor', 'value': '123'},
#  'device2': {'name': 'Motor', 'value': '456'}}

Яндекс

# Таблица умножения 10x10
table = ...  # TODO: nested list comprehension

# Ожидаемый результат: [[1,2,3...10], [2,4,6...20], ...]

ASYNC

Riot Games

# Параллельные HTTP запросы без блокировки
async def fetch_all(urls: list[str]) -> list[str]:
    # TODO: загрузить все URL параллельно через aiohttp
    pass

async def fetch_one(session, url):
    # TODO: загрузить один URL
    pass

Типичная задача (FAANG)

# Producer-Consumer с asyncio.Queue
async def producer(queue: asyncio.Queue):
    # TODO: генерировать элементы и класть в очередь
    pass

async def consumer(queue: asyncio.Queue):
    # TODO: читать из очереди и обрабатывать
    pass

Типичная задача (FAANG)

# Retry с exponential backoff (async версия)
async def fetch_with_retry(url: str, max_retries: int = 5):
    # TODO: повторять запрос с задержкой 1, 2, 4, 8, 16 сек
    pass

Типичная задача (FAANG)

# Rate limiting через Semaphore
async def fetch_with_limit(urls: list[str], max_concurrent: int = 10):
    # TODO: загрузить все URL, но не более max_concurrent одновременно
    pass

BACKEND

Revolut

# Money Transfer API — атомарные транзакции
# POST /transfer
# Критично: race conditions, rollback при ошибке

class TransferService:
    async def transfer(self, from_id: int, to_id: int, amount: Decimal):
        # TODO: реализовать атомарный перевод
        # - проверить баланс отправителя
        # - заблокировать обе записи (SELECT FOR UPDATE)
        # - выполнить дебет и кредит
        # - откатить при ошибке
        pass

VK

# Каталог товаров с пагинацией и кешированием
# GET /api/goods/byprice?count=20&offset=0

@app.get("/api/goods/byprice")
async def get_goods(count: int = 20, offset: int = 0):
    # TODO: реализовать с Redis кешем
    # - проверить кеш
    # - если нет — запросить из БД
    # - сохранить в кеш с TTL
    pass

Яндекс

# Написать тесты к существующему коду (дают готовый код, 1 час)

@pytest.fixture
async def client():
    # TODO: создать тестовый клиент
    pass

async def test_create_user(client):
    # TODO: тест создания пользователя
    pass

async def test_create_user_duplicate(client):
    # TODO: тест на дубликат (ожидаем 409)
    pass

LRU Cache (Microsoft, Google, Amazon)

# O(1) get и put
class LRUCache:
    def __init__(self, capacity: int):
        # TODO: инициализация
        pass

    def get(self, key: int) -> int:
        # TODO: вернуть значение, обновить "недавность"
        pass

    def put(self, key: int, value: int) -> None:
        # TODO: добавить/обновить, удалить старейший если переполнение
        pass

cache = LRUCache(2)
cache.put(1, 'a')
cache.put(2, 'b')
cache.get(1)      # 'a' — теперь 1 most recently used
cache.put(3, 'c') # удаляет 2
cache.get(2)      # -1 (не найден)

URL Shortener (System Design + Code)

# POST /shorten → короткая ссылка
# GET /{code} → редирект

class URLShortener:
    def __init__(self):
        # TODO: инициализация хранилища
        pass

    def shorten(self, url: str) -> str:
        # TODO: сгенерировать короткий код (Base62)
        pass

    def resolve(self, code: str) -> str | None:
        # TODO: вернуть оригинальный URL
        pass

Pagination API (Junior/Middle)

# GET /tasks?limit=10&offset=0&sort=created_at&order=desc&status=active

@app.get("/tasks")
async def get_tasks(
    limit: int = Query(10, le=100),
    offset: int = Query(0, ge=0),
    sort: str = Query("created_at"),
    order: str = Query("desc"),
    status: str | None = Query(None)
):
    # TODO: реализовать фильтрацию, сортировку, пагинацию
    # Вернуть: {"items": [...], "total": N, "limit": L, "offset": O}
    pass

Компании

Компания Категория Задача
Squarespace Decorators Memoize
Minted Decorators Throttle
Squarepoint Capital Decorators Typed decorator
Яндекс Decorators Timing с параметром
Morgan Stanley Generators Fibonacci
Airbnb Generators Flatten nested list
Stripe/Google/Amazon Generators Batch file processing
J.P. Morgan Comprehensions Powers generation
Jump Trading Comprehensions Matrix transpose
Goldman Sachs Comprehensions Flatten + dict
Bloomberg Comprehensions Group by key
Tinkoff Comprehensions Nested dict transform
Riot Games Async Parallel HTTP
Revolut Backend Money transfer
VK Backend Catalog + cache
Hudson River Trading Generators Build a generator
Microsoft/Google Backend LRU Cache
Revolut Backend Money Transfer API
VK Backend Catalog + cache
Яндекс Backend Pytest тесты
System Design Backend URL Shortener
Junior/Middle Backend Pagination API

Типичные ошибки на лайвкодинге

Заблуждение: декоратор -- это просто обёртка print-ами

На интервью ожидают @functools.wraps(func) для сохранения __name__, __doc__. Без него debugger, help(), pickle -- все ломаются. Забыть wraps -- моментальный красный флаг для Senior-позиций.

Заблуждение: генератор и список -- одно и то же, только лениво

Генератор нельзя перебрать дважды, у него нет len(), [] и reversed(). Если интервьюер просит "обработать файл в 10GB батчами" и вы возвращаете list -- это провал. Генератор для 1M элементов -- O(1) по памяти вместо O(n).

Заблуждение: asyncio ускоряет любой код

async/await ускоряет только I/O-bound задачи (сеть, диск). Для CPU-bound (вычисления, ML inference) asyncio бесполезен -- нужен multiprocessing. На интервью часто спрашивают: "Когда async НЕ поможет?"


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

"Напишите декоратор мемоизации"

❌ Слабый ответ: обёртка без @wraps, без обработки unhashable аргументов, без ограничения размера кэша

✅ Сильный ответ: @wraps(func), dict как кэш с ключом (args, tuple(sorted(kwargs.items()))), упоминание @functools.lru_cache как стандартного решения

"Реализуйте LRU Cache с O(1) get/put"

❌ Слабый ответ: dict + list (O(n) удаление из середины)

✅ Сильный ответ: OrderedDict с move_to_end() или dict + doubly-linked list. Упоминание что в Python 3.7+ dict сохраняет порядок, но не имеет move_to_end()

"Flatten вложенного списка произвольной глубины"

❌ Слабый ответ: рекурсия без проверки типа, падает на строках ("abc" -- iterable!)

✅ Сильный ответ: isinstance(item, Iterable) and not isinstance(item, (str, bytes)), или yield from для рекурсивного генератора


Related: - Python Language Features Interview (deep dives on decorators, generators, async) - Python Gotchas & Tricky Questions (edge cases to know) - Python Interview Sources (URL collection)


2025-12-23