Python вопросы с собеседований
Вопросы с собеседований по Python @workakkk - админ @machinelearning_interview - вопросы с собесдований по Ml @pro_python_code - Python @data_analysis_ml - анализ данных на Python @itchannels_telegram - 🔥 главное в ит РКН: clck.ru/3FmrFd
Mostrar más📈 Análisis del canal de Telegram Python вопросы с собеседований
El canal Python вопросы с собеседований (@python_job_interview) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 24 822 suscriptores, ocupando la posición 5 258 en la categoría Tecnologías y Aplicaciones y el puesto 26 472 en la región Rusia.
📊 Métricas de audiencia y dinámica
Desde su creación el невідомо, el proyecto ha mostrado un crecimiento acelerado, reuniendo a 24 822 suscriptores.
Según los últimos datos del 25 agosto, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -44, y en las últimas 24 horas de 0, conservando un alto alcance.
- Estado de verificación: No verificado
- Tasa de interacción (ER): El promedio de interacción de la audiencia es 6.01%. Durante las primeras 24 horas tras publicar, el contenido suele obtener 2.76% de reacciones respecto al total de suscriptores.
- Alcance de las publicaciones: Cada publicación recibe en promedio 1 492 visualizaciones. En el primer día suele acumular 684 visualizaciones.
- Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 6.
- Intereses temáticos: El contenido se centra en temas clave como github, api, собеседование, git, docker.
📝 Descripción y política de contenido
El autor describe el recurso como un espacio para expresar opiniones subjetivas:
“Вопросы с собеседований по Python
@workakkk - админ
@machinelearning_interview - вопросы с собесдований по Ml
@pro_python_code - Python
@data_analysis_ml - анализ данных на Python
@itchannels_telegram - 🔥 главное в ит
РКН: clck.ru/3FmrFd”
Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 28 agosto, 2026), el canal mantiene la vigencia y un amplio alcance. La analítica demuestra que la audiencia interactúa activamente con el contenido, lo que lo convierte en un punto de referencia dentro de la categoría Tecnologías y Aplicaciones.
{user_input}
\"\n\n# Предположим, функция html() экранирует опасные символы\nsafe_output = html(template)\n\n\nЗачем это нужно?\n\nИдея проста: обеспечить безопасность по умолчанию при работе с внешними данными. Сегодня f-строки невероятно удобны, но могут стать причиной уязвимостей, если не учитывать контекст.\n\nПример:\n\n\n# Опасный подход с f-строкой\nquery = f\"SELECT * FROM users WHERE name = '{user_input}'\"\n\n\nС t-строками можно заранее создать шаблон и безопасно вставить данные позже, минимизируя риски.\n\nПочему мнения разделились?\n\nМногие разработчики задаются вопросом: зачем ещё один способ форматирования строк, если уже есть:\n\n- старые добрые `%`-форматирование,\n- метод .format(),\n- f-строки,\n- и сторонние шаблонизаторы вроде Jinja2.\n\nНекоторые опасаются, что добавление нового синтаксиса лишь усложнит язык без серьёзной необходимости.\n\nСторонники t-строк, однако, видят их потенциал в упрощении безопасной работы с текстом прямо в стандартной библиотеке Python.\n\nЗаключение\n\nT-строки — это попытка добавить в Python инструмент, который обеспечит безопасность шаблонов без привлечения сторонних библиотек. Будет ли это востребовано или останется малоиспользуемой функцией? Время покажет.\n\n🔗 Полное описание: [PEP 750](https://peps.python.org/pep-0750/)\n\nА как ты относишься к новым t-строкам? 💬","datePublished":"2025-05-07T16:53:03Z","dateModified":"2025-05-07T16:53:03Z","author":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"publisher":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"commentCount":2,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":3334},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":28},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":22},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":2}]}},{"@type":"ListItem","position":16,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1101","url":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1101","mainEntityOfPage":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1101","headline":"📝 Как составить резюме, чтобы попасть в Magnificent 7: анализ кейса Недавно инженер поделился своим резюме, к…","articleBody":"📝 Как составить резюме, чтобы попасть в Magnificent 7: анализ кейса\n\nНедавно инженер поделился своим резюме, которое помогло ему получить предложение работы от одной из rjvgfybb Magnificent 7 (Apple, Microsoft, Google, Amazon, Meta, Nvidia, Tesla).\n\nMagnificent 7 (в переводе — «Великолепная семёрка») — это современное неофициальное название семи крупнейших и самых влиятельных технологических компаний США, которые лидируют на фондовом рынке, в инновациях и в масштабе бизнеса.\n\nРазберём, что сделало его резюме успешным и чему можно научиться.\n\n📌 Главные выводы из резюме:\n\n1. Фокус на достижениях, а не обязанностях.\n\nМногие кандидаты в резюме просто перечисляют, *что они делали*, например:\n\n- “Разрабатывал API”\n- “Поддерживал базу данных”\n- “Писал скрипты для автоматизации”\n\n⚠️ Это описывает обязанности, но не показывает ценность или результат работы.\n\nВ успешном резюме инженер вместо этого написал, чего он достиг благодаря своей работе:\n\n✅ “Разработал API, который сократил время обработки данных на 30%” \n✅ “Оптимизировал запросы к базе данных, уменьшив среднее время ответа с 2 секунд до 0.5 секунд” \n✅ “Автоматизировал процесс деплоя, снизив количество ошибок на 15%”\n\nТакой подход показывает, как конкретно ваша работа помогла команде или бизнесу. \nРаботодатель видит результаты, которые вы приносите, а не просто описание того, что вы делали.\n\n💡 Почему это важно?\n\nBig Tech-компании ищут инженеров, которые:\n\n- Умеют оценивать влияние своей работы\n- Думают о метриках успеха\n- Приносят измеримый результат\n\nЕсли в резюме нет цифр, улучшений или влияния на процесс — работодатель сам должен это додумывать. \nА успешное резюме снимает вопросы и сразу показывает: “Вот что я сделал, вот как я улучшил продукт/процесс/результат.”\n\n\n2. Лаконичность и компактность.\n\n✅ 1 страница \n✅ Чёткая структура: “Опыт”, “Навыки”, “Образование” \n✅ Без фото, графиков, цветных рамок — чистый текст\n\n3. Цифры везде, где это возможно.\n\nЛюбое достижение сопровождается конкретной метрикой: улучшение производительности, сокращение времени, рост количества пользователей. \nДаже небольшие улучшения указаны численно.\n\n4. Поддержка через проекты с открытым кодом.\n\nИнженер приложил ссылку на GitHub с реальными проектами — это усилило доверие к нему Как с специалисту.\n\n5. Навыки — только релевантные вакансии.\n\nВ разделе Skills нет «MS Word» или «PowerPoint». \nТолько языки, технологии, инструменты, которые нужны для позиции (Python, Kubernetes, CI/CD, etc.).\n\n6. Интерншипы и стажировки — это опыт.\n\nКаждый опыт, даже в рамках стажировки, описан с результатами. \nВакансии в топ-компаниях ценят любую практику в реальной команде.\n\n---\n\n🎯 Что важно для Big Tech:\n\n✅ Результаты > Задачи. \n✅ Цифры. \n✅ 1 страница. \n✅ GitHub/портфолио. \n✅ Релевантные навыки.\n\n---\n\n🔥 Совет:\n\nВаше резюме — это реклама вас как продукта. \nПокажите пользу, которую вы можете принести, а не просто список обязанностей.\n\n➡️ Статья","datePublished":"2025-05-06T10:00:15Z","dateModified":"2025-05-06T10:00:15Z","author":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"publisher":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"commentCount":3,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":2674},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":15},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":42},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3}]}},{"@type":"ListItem","position":17,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1100","url":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1100","mainEntityOfPage":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1100","headline":"🌟 Dynaconf — управление конфигурациями в Python без головной боли. Этот проект предлагает унифицированный спо…","articleBody":"🌟 Dynaconf — управление конфигурациями в Python без головной боли. Этот проект предлагает унифицированный способ работы с конфигурациями: от простых .toml-файлов до интеграции с Hashicorp Vault для хранения секретов. \n\nПроект выделяет из общей массы поддержка 5+ форматов с автоматическим парсинго, разделение настроек по средам, защита секретов через .gitignore и возможность использовать Redis/Vault. Для старта достаточно pip install dynaconf и одной команды dynaconf init, которая сгенерирует все необходимые файлы. \n\n🤖 GitHub\n\n@python_job_interview","datePublished":"2025-05-05T14:41:01Z","dateModified":"2025-05-05T14:41:01Z","author":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"publisher":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":2284},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":8},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":19}]}},{"@type":"ListItem","position":18,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1099","url":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1099","mainEntityOfPage":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1099","headline":"Порекомендуйте друга в Ozon Tech и получите 150 000 ₽. Важно: IT-команда ведущего e-com ищет специалистов уро…","articleBody":"Порекомендуйте друга в Ozon Tech и получите 150 000 ₽. \n\nВажно: IT-команда ведущего e-com ищет специалистов уровня senior+ в Data Science. Программа работает для тех, кто не работает в Ozon. \n\nПодробнее о том, за какие вакансии можно получить вознаграждение, здесь ⬅️","datePublished":"2025-05-05T12:41:43Z","dateModified":"2025-05-26T14:08:46Z","author":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"publisher":{"@type":"Organization","name":"Python вопросы с собеседований","url":"https://telemetr.io/es/channels/1635717658-python_job_interview","image":"https://img.tlmtr.io/c/1MHiSS/5474186619528527464?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":2482},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":2},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":7}]}},{"@type":"ListItem","position":19,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1098","url":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1098","mainEntityOfPage":"https://telemetr.io/es/channels/1635717658-python_job_interview/posts/1098","headline":"🧩 Python‑задача: построить резолвер зависимостей для «мини‑PyPI» Нужно написать ядро пакетного менеджера — ал…","articleBody":"🧩 Python‑задача: построить резолвер зависимостей для «мини‑PyPI»\n\nНужно написать ядро пакетного менеджера — алгоритм, выбирающий набор совместимых версий библиотек под заданные ограничения. \nЗадача напоминает работу pip, npm или cargo, но в упрощённом формате, достаточном для тренировки графовых алгоритмов, backtracking и оптимизаций.\n\n## 📜 Входные данные\n\n1. catalog.json — «репозиторий» пакетов. \n \n {\n \"pandas\": {\n \"1.1.0\": { \"depends\": { \"numpy\": \">=1.17,<1.20\" } },\n \"1.3.5\": { \"depends\": { \"numpy\": \">=1.19,<1.22\", \"python-dateutil\": \">=2.7\" } }\n },\n \"numpy\": {\n \"1.18.5\": { \"depends\": {} },\n \"1.19.2\": { \"depends\": {} },\n \"1.21.0\": { \"depends\": {} }\n },\n \"python-dateutil\": {\n \"2.8.0\": { \"depends\": { \"six\": \">=1.5\" } },\n \"2.8.2\": { \"depends\": { \"six\": \">=1.5\" } }\n },\n \"six\": {\n \"1.14.0\": { \"depends\": {} },\n \"1.16.0\": { \"depends\": {} }\n }\n }\n \n *Ключ* — имя пакета; *значения* — версии → словарь зависимостей (`depends`). \n У каждой зависимости указан диапазон версий по SemVer‑синтаксису >=a, ge: 18 для чисел или вложенных структур. Сборка требует Rust toolchain, но результат стоит того: например, валидация списка из 10к элементов занимает миллисекунды.
🤖 GitHub
@python_interviewlambda, отложенное выполнение
📌 Условие
Что выведет следующий код?
funcs = []
for i in range(5):
funcs.append(lambda: i)
results = [f() for f in funcs]
print(results)
❓ Вопросы
1. Почему вывод может не соответствовать ожиданиям [0, 1, 2, 3, 4]?
2. Что именно "запоминает" lambda внутри цикла?
3. Как переписать код, чтобы результат был [0, 1, 2, 3, 4]?
🔍 Разбор
✅ Ожидаемый (неправильный) вывод:
[4, 4, 4, 4, 4]🔧 Почему так происходит - Все
lambda внутри funcs замыкают одну и ту же переменную `i`.
- К моменту выполнения f() переменная i уже равна 4 — и так для всех функций.
⚠️ Подвох
lambda: i не захватывает значение, а ссылается на переменную, которая будет изменяться при каждой итерации цикла.
В итоге — все lambda ссылаются на одно и то же `i`, которое стало равно 4 к концу цикла.
🧠 Решение
Нужно "зафиксировать" значение i, передав его как аргумент по умолчанию в lambda:
for i in range(5):
funcs.append(lambda i=i: i)
Теперь результат будет:
[0, 1, 2, 3, 4]📌 Это один из самых частых подвохов в Python, особенно при использовании лямбда-функций в генераторах и UI-коллбеках.
list и dict
📌 Условие
Что выведет следующий код?
def append_to_list(value, my_list=[]):
my_list.append(value)
return my_list
print(append_to_list(1))
print(append_to_list(2))
print(append_to_list(3))
❓ Вопросы
1. Почему результат выглядит неожиданно?
2. Как исправить это поведение?
3. Когда стоит использовать изменяемые аргументы по умолчанию — если вообще стоит?
🔍 Разбор
✅ Ожидаемый вывод:
[1] [1, 2] [1, 2, 3]🔧 Почему так происходит - Аргументы по умолчанию вычисляются один раз — во время определения функции, а не при каждом вызове. - Значение
my_list=[] создаётся один раз и затем используется повторно при всех вызовах.
- Все вызовы append_to_list изменяют один и тот же список.
⚠️ Подвох
Это один из самых коварных багов в Python, особенно среди начинающих — кажется, что my_list должен быть новым на каждый вызов, но это не так.
🧠 Вывод
- Никогда не используй изменяемые типы (list, dict, set) как значения по умолчанию.
- Вместо этого используй None и создавай новый объект вручную:
def append_to_list(value, my_list=None):
if my_list is None:
my_list = []
my_list.append(value)
return my_list
✅ Тогда вывод будет:
[1] [2] [3]📌 Это правило относится ко всем изменяемым типам:
[], {}, set() и кастомные классы.
@python_job_interview Depends(RateLimiter(times=2, seconds=5)) к эндпоинту и он начнет отклонять запросы после двух обращений в пятисекундном окне. Под капотом работает Lua-скрипт, который эффективно считает запросы без лагов.
Интересные фишки:
— Поддержка вебсокетов через WebSocketRateLimiter
— Кастомизация идентификаторов
— Множественные лимиты на один роут
🤖 GitHub
@python_job_interviewcounter(start), которая возвращает функцию-счётчик. Каждый вызов этой функции увеличивает значение на 1.
Пример:
c = counter(10)
print(c()) # 11
print(c()) # 12
print(c()) # 13
d = counter(100)
print(d()) # 101
print(c()) # 14 ← работает независимо
🎯 Подвох:
- Нельзя использовать глобальные переменные
- Нужно использовать замыкание
- Без nonlocal — не заработает
✅ Решение:
def counter(start):
count = start
def inner():
nonlocal count
count += 1
return count
return inner
# Проверка
a = counter(5)
print(a()) # 6
print(a()) # 7
b = counter(100)
print(b()) # 101
print(a()) # 8
🧠 Объяснение подвоха:
- counter возвращает функцию, внутри которой count сохраняется в замыкании
- nonlocal нужен, чтобы изменить внешнюю переменную, а не просто читать её
- Каждое замыкание имеет своё независимое состояние
⚠️ Без nonlocal count, Python создаст локальную count внутри inner(), и UnboundLocalError — гарантирован
🛠️ Применяется в:
• Реализации генераторов состояния
• Мини-хранилищах внутри функций
• Кеширующих функциях и декораторах
@python_job_interviewcollections.defaultdict(list) для удобства, и пишете такой код:
from collections import defaultdict
actions = defaultdict(list)
def track(user_id, action):
actions[user_id].append(action)
track('alice', 'login')
track('bob', 'view')
track('alice', 'logout')
# Теперь вы хотите скопировать этот словарь
copy_actions = actions.copy()
# Допишем в оригинал
track('bob', 'logout')
# Посмотрим, как выглядит копия
print(copy_actions['bob']) # Что будет напечатано?
🧠 Вопрос:
Что будет напечатано? Почему?
Как сделать так, чтобы copy_actions не изменился при добавлении новых действий в actions?
💥 Подвох
Метод copy() копирует только верхний уровень словаря. То есть, списки значений не копируются — это всё те же самые объекты в памяти. Поэтому при track('bob', 'logout') список actions['bob'] изменяется, и это тот же самый список, что лежит в copy_actions['bob'].
➡️ Ответ: print(copy_actions['bob']) напечатает ['view', 'logout'].
✅ Как правильно?
Чтобы избежать такой проблемы, используйте глубокое копирование:
import copy
copy_actions = copy.deepcopy(actions)
Теперь copy_actions не изменится при дальнейшем редактировании actions.
📌 Вывод
Даже опытные разработчики иногда забывают: copy() не копирует вложенные структуры данных!
Если в значениях словаря лежат мутабельные объекты, обязательно подумайте — а не нужен ли вам deepcopy()?
🧪 Попробуйте изменить defaultdict(list) на обычный dict — и посмотрите, что изменится.def update_dict(key, value, d={}):
d[key] = value
return d
dict1 = update_dict('a', 1)
dict2 = update_dict('b', 2, {})
dict3 = update_dict('c', 3)
print("dict1 =", dict1)
print("dict2 =", dict2)
print("dict3 =", dict3)
— Варианты ответа:
A.
dict1 = {'a': 1}
dict2 = {'b': 2}
dict3 = {'c': 3}
B.
dict1 = {'a': 1, 'c': 3}
dict2 = {'b': 2}
dict3 = {'a': 1, 'c': 3}
C.
dict1 = {'a': 1}
dict2 = {'b': 2}
dict3 = {'a': 1, 'c': 3}
Какой из этих ответов правильный и почему?🧐
— Подсказка: аргументы по умолчанию в Python вычисляются только один раз - при определении функции. Словарь, как и список, является изменяемым объектом.
В функции update_dict параметр d={} создается один раз и используется для всех вызовов, где не передается явно другой словарь.
— Правильный ответ: B
Объяснение:
1️⃣ dict1 = update_dict('a', 1) → используется словарь по умолчанию → {'a': 1}
2️⃣ dict2 = update_dict('b', 2, {}) → создан новый словарь → {'b': 2}
2️⃣ dict3 = update_dict('c', 3) → снова используется исходный словарь → {'a': 1, 'c': 3}
4️⃣ dict1 тоже изменится, так как это ссылка на тот же объект → {'a': 1, 'c': 3}
Итоговый вывод:
dict1 = {'a': 1, 'c': 3}
dict2 = {'b': 2}
dict3 = {'a': 1, 'c': 3}
@python_job_interviewt перед строкой, например:
t"Привет, {name}!"
Но ключевое отличие: вместо немедленного преобразования переменных в строку, как это делает f-строка, t-строка создаёт объект Template, который можно обработать позже. Это позволяет, например, безопасно подставлять пользовательские данные, снижая риск атак (XSS, SQL-инъекции и др.).
Пример использования:
from string.templatelib import Template
user_input = "<script>alert('XSS')</script>"
template = t"<p>{user_input}</p>"
# Предположим, функция html() экранирует опасные символы
safe_output = html(template)
Зачем это нужно?
Идея проста: обеспечить безопасность по умолчанию при работе с внешними данными. Сегодня f-строки невероятно удобны, но могут стать причиной уязвимостей, если не учитывать контекст.
Пример:
# Опасный подход с f-строкой
query = f"SELECT * FROM users WHERE name = '{user_input}'"
С t-строками можно заранее создать шаблон и безопасно вставить данные позже, минимизируя риски.
Почему мнения разделились?
Многие разработчики задаются вопросом: зачем ещё один способ форматирования строк, если уже есть:
- старые добрые `%`-форматирование,
- метод .format(),
- f-строки,
- и сторонние шаблонизаторы вроде Jinja2.
Некоторые опасаются, что добавление нового синтаксиса лишь усложнит язык без серьёзной необходимости.
Сторонники t-строк, однако, видят их потенциал в упрощении безопасной работы с текстом прямо в стандартной библиотеке Python.
Заключение
T-строки — это попытка добавить в Python инструмент, который обеспечит безопасность шаблонов без привлечения сторонних библиотек. Будет ли это востребовано или останется малоиспользуемой функцией? Время покажет.
🔗 Полное описание: [PEP 750](https://peps.python.org/pep-0750/)
А как ты относишься к новым t-строкам? 💬 pip install dynaconf и одной команды dynaconf init, которая сгенерирует все необходимые файлы.
🤖 GitHub
@python_job_interviewpip, npm или cargo, но в упрощённом формате, достаточном для тренировки графовых алгоритмов, backtracking и оптимизаций.
## 📜 Входные данные
1. catalog.json — «репозиторий» пакетов.
{
"pandas": {
"1.1.0": { "depends": { "numpy": ">=1.17,<1.20" } },
"1.3.5": { "depends": { "numpy": ">=1.19,<1.22", "python-dateutil": ">=2.7" } }
},
"numpy": {
"1.18.5": { "depends": {} },
"1.19.2": { "depends": {} },
"1.21.0": { "depends": {} }
},
"python-dateutil": {
"2.8.0": { "depends": { "six": ">=1.5" } },
"2.8.2": { "depends": { "six": ">=1.5" } }
},
"six": {
"1.14.0": { "depends": {} },
"1.16.0": { "depends": {} }
}
}
*Ключ* — имя пакета; *значения* — версии → словарь зависимостей (`depends`).
У каждой зависимости указан диапазон версий по SemVer‑синтаксису >=a,<b.
2. requirements.txt — то, что хочет пользователь:
pandas>=1.1,<1.4 python-dateutil==2.8.2## 🔧 Задача Написать функцию
resolve(catalog: dict[str, dict[str, dict]],
requirements: list[str]) -> dict[str, str]
которая возвращает словарь
{package: chosen_version} — единственную консистентную конфигурацию, удовлетворяющую всем ограничениям, *либо* возбуждает UnresolvableError.
### Правила
1. Версия должна лежать в пересечении *всех* диапазонов, навешанных на пакет.
2. Если диапазон пуст — конфликты нельзя игнорировать.
3. Разрешение идёт по принципу «самая новая подходящая версия» (Greedy‑latest), но если она приводит к заведомому конфликту, надо откатиться («backtrack») и попробовать более старую.
4. Каталог может быть большим (≥ 10 000 пакетов), алгоритм должен укладываться в секунды.
5. Допустимо использовать только стандартную библиотеку + packaging.version/packaging.specifiers (pip‑compatible сравнение версий).
## 🏁 Дополнительные челленджи
* Кэшировать результаты проверки диапазонов, чтобы не пересчитывать одно и то же.
* Оптимизировать порядок обхода графа (например, сначала пакеты с меньшим числом разрешимых версий).
* Добавить «экзотики»: опциональные зависимости, extras (`pandas[perf]`) или marker‑выражения (`sys_platform == "linux"`).
---
# ✅ Референс‑решение (однофайловое, python 3.11)
> *Не читайте решение в комментариях, пока не попробуете решить сами!*
@python_job_interview