Python вопросы с собеседований
Вопросы с собеседований по Python @workakkk - админ @machinelearning_interview - вопросы с собесдований по Ml @pro_python_code - Python @data_analysis_ml - анализ данных на Python @itchannels_telegram - 🔥 главное в ит РКН: clck.ru/3FmrFd
Больше📈 Аналитический обзор Telegram-канала Python вопросы с собеседований
Канал Python вопросы с собеседований (@python_job_interview) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 24 967 подписчиков, занимая 5 488 место в категории Технологии и приложения и 26 804 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 24 967 подписчиков.
Согласно последним данным от 05 июня, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -153, а за последние 24 часа — -5, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 6.12%. В первые 24 часа после публикации контент обычно набирает 3.05% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 1 527 просмотров. В течение первых суток публикация набирает 762 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 8.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как github, api, собеседование, git, docker.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Вопросы с собеседований по Python
@workakkk - админ
@machinelearning_interview - вопросы с собесдований по Ml
@pro_python_code - Python
@data_analysis_ml - анализ данных на Python
@itchannels_telegram - 🔥 главное в ит
РКН: clck.ru/3FmrFd”
Благодаря высокой частоте обновлений (последние данные получены 06 июня, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
t перед строкой, например:
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_interviewSmartCache, который работает следующим образом:
- Метод put(key: str, value: Any):
- Сохраняет значение по ключу.
- Если суммарный объем памяти, занимаемый всеми элементами, превышает лимит (например, 10 MB), автоматически удаляются наименее "ценные" элементы.
- Метод get(key: str) -> Any:
- Возвращает значение по ключу.
- Увеличивает счётчик использования элемента.
- Если элемент отсутствует — возвращает None.
Что значит "ценность" элемента:
- Ценность = количество обращений (`hit count`) к элементу.
- При очистке кэша сначала удаляются элементы с наименьшим количеством обращений.
Ограничения:
- Класс должен корректно считать объём памяти, занимаемый элементами.
- Нужно учитывать, что элементы могут быть сложными структурами (`dict`, list, вложенные объекты).
- Решение должно быть эффективным: операции должны быть быстрыми даже при большом количестве элементов.
---
▪️ Подсказки:
- Для оценки размера объектов можно использовать модуль sys.getsizeof, но для сложных вложенных структур нужен рекурсивный подсчет.
- Для хранения частоты обращений стоит использовать дополнительную структуру данных (`collections.Counter` или `dict`).
- При очистке лучше сначала группировать элементы по "ценности", а затем удалять самые "дешевые".
---
▪️ Что оценивается:
- Умение работать с ограничениями по памяти.
- Аккуратная обработка ссылок и размеров объектов.
- Эффективность очистки кэша.
- Чистота и читаемость кода.
---
▪️ Разбор возможного решения:
Идея архитектуры:
- Храним:
- storage: словарь {key: value}.
- hits: счётчик {key: hit_count}.
- size: общий размер всех объектов.
- При put():
- Добавляем элемент.
- Пересчитываем суммарный размер.
- Если размер превышает лимит:
- Удаляем наименее популярные элементы до тех пор, пока не уложимся в лимит.
- При get():
- Увеличиваем hit_count элемента.
- Возвращаем значение или None.
Оценка размера объектов:
- Простого sys.getsizeof недостаточно для коллекций.
- Нужна функция, рекурсивно подсчитывающая размер всех вложенных объектов.
Мини-пример функции подсчета размера:
import sys
def deep_getsizeof(obj, seen=None):
"""Рекурсивно считает память объекта и его вложенных объектов"""
size = sys.getsizeof(obj)
if seen is None:
seen = set()
obj_id = id(obj)
if obj_id in seen:
return 0
seen.add(obj_id)
if isinstance(obj, dict):
size += sum([deep_getsizeof(v, seen) + deep_getsizeof(k, seen) for k, v in obj.items()])
elif isinstance(obj, (list, tuple, set, frozenset)):
size += sum(deep_getsizeof(i, seen) for i in obj)
return size
Мини-пример интерфейса `SmartCache`:
class SmartCache:
def __init__(self, max_size_bytes):
self.max_size = max_size_bytes
self.storage = {}
self.hits = {}
self.total_size = 0
def put(self, key, value):
# добавить логику добавления и очистки при переполнении
pass
def get(self, key):
# увеличить hit_count и вернуть значение
pass
🔖 Дополнительные вопросы:
- Как ускорить очистку кэша без полного перебора всех элементов?
- Как сделать потокобезопасную версию кэша?
- Как адаптировать SmartCache для распределённой архитектуры (кэш между несколькими машинами)?
@python_job_interviewВ первой строке заданы два натуральных числа N и M (0 < N, M ≤ 100 000). Во второй строке перечислены N элементов первого множества (целые числа через пробел). В третьей строке — M элементов второго множества (целые числа через пробел). Все числа по модулю не превышают 10<sup>9</sup>.— Выходные данные
Для каждого из M чисел выведите в отдельной строке: - "IN", если число присутствует в обоих множествах - "OUT", если число есть только в одном из множеств - "MISS", если числа нет ни в одном множестве— Примеры: Входные данные:
5 4 10 20 30 40 50 20 25 40 60Выходные данные:
IN OUT IN MISSЖду ваших вариантов решений 📝 @python_job_interview
name = "Alice"
greeting = t"Hello, {name}!" # t-строка
Вместо немедленной подстановки, как в f"...", t"..." создает шаблон с выражениями как параметрами.
🔐 Зачем это нужно?
✅ Безопасность при генерации SQL, HTML, JSON
✅ Улучшение инструментов и проверки типов (через static analysis)
✅ Контроль над контекстом исполнения (больше нельзя просто вставить переменную как есть — нужно передать её явно)
📦 Использование:
t-строки — это первый шаг к "template string literals" как в TypeScript.
Можно использовать с функциями:
def html(template: T[str]) -> SafeHTML:
...
html(t"<div>{user_input}</div>")
💡 Почему это важно?
Старый код:
f"SELECT * FROM users WHERE name = '{user_name}'"
может привести к SQL-инъекциям и XSS.
t-строки — безопасная альтернатива с встроенной защитой.
🛡 Пример: безопасный HTML
template = t"<p>{user_input}</p>"
html_output = html(template)
# <p><script>alert('bad')</script></p>
Функция html() может вернуть не просто строку, а полноценный HTMLElement.
Больше никакой "грязи" — всё чисто и типобезопасно.
🔍 Работа с шаблоном
t-строки позволяют получить доступ к содержимому:
template = t"Hello {name}!"
template.strings # ("Hello ", "!")
template.values # (name,)
template.interpolations[0].format_spec # ">8"
Можно и вручную собрать шаблон:
Template("Hello ", Interpolation(value="World", expression="name"), "!")
🚀 Вывод:
t"..." — шаг к безопасным шаблонам и типизации строк в Python.
Готовься к будущему Python — безопасному по умолчанию.
📌 Подробнее здесь
@pythonlВ первой строке входных данных содержатся натуральные числа N и К ( 0 < N, K ≤ 100 000). Во второй строке задаются N элементов первого массива, отсортированного по возрастанию, а в третьей строке - К элементов второго массива. Элементы обоих массивов - целые числа, каждое из которых по модулю не превосходит 109— Выходные данные
Требуется для каждого из К чисел вывести в отдельную строку "YES", если это число встречается в первом массиве, и "NO" в противном случае.— Примеры: входные данные
10 5 123 4 5 6 7 8 9 10 -2 0 4 9 12выходные данные
NO NO YES YES NOСкидывайте свои решения в комментарии🧐 @python_job_interview
mydaemon), который запускается через systemd unit и, согласно логам, должен работать постоянно.
❓ Но вот странность:
systemctl status mydaemon показывает, что сервис активен.
Однако при выполнении ps aux | grep mydaemon — процесса в списке нет.
top, htop, pgrep, pidof — тоже ничего не показывают.
Но при перезапуске systemd-сервиса (systemctl restart mydaemon) — в логах появляется запись о запуске, ошибок нет, а поведение не меняется.
Вопрос:
что происходит и как найти реальный процесс?Подсказки: Попробуйте посмотреть, какой тип сервиса указан в systemd unit-файле. Изучите, куда уходит stdout/stderr
.
Подумайте, может ли ExecStart запускать shell-обёртку, а не сам процесс.
Что покажет systemctl show -p MainPID mydaemon?
Подвох и решение:
Часто в unit-файле могут писать:
```ini
Type=simple
ExecStart=/bin/bash -c 'sleep 9999'```
Systemd считает, что bash — это основной процесс (MainPID), но он сразу завершается, передав выполнение sleep. Однако поскольку Type=simple, systemd не отслеживает дочерние процессы, и MainPID исчезает — ps и pgrep по имени mydaemon ничего не покажут, а дочерний процесс (sleep 9999) работает, но под другим именем.
Решение:
Либо указать Type=forking и использовать PIDFile.
Либо не использовать bash -c, а запускать нужный бинарь напрямую.
Либо использовать Type=exec (в systemd >240) или Type=notify с proper daemon tools.user, login/logout).
Найди тех, кто зашел, но не вышел.
📜 Пример:
logs = [
("alice", "login"),
("bob", "login"),
("alice", "logout"),
("dave", "login"),
("bob", "logout"),
("carol", "login"),
("dave", "logout")
]
________
💻 Решение:
from collections import defaultdict
def find_stuck_users(logs):
counter = defaultdict(int)
for user, action in logs:
if action == "login":
counter[user] += 1
elif action == "logout":
counter[user] -= 1
return sorted([user for user, count in counter.items() if count > 0])
🛠Ответ: "carol"
#Python #Challenge #DevPuzzle
@python_job_interview
def extendList(val, list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')
print("list1 =", list1)
print("list2 =", list2)
print("list3 =", list3)
Варианты ответа:
A.
list2 = [123]
list3 = ['a']
B.
list2 = [123]
list3 = [10, 'a']
C.
list2 = [123]
list3 = [10, 'a']
D.
list2 = [123]
list3 = ['a']
❓ Как думаешь, какой ответ правильный и почему?
Подвох: аргументы по умолчанию в Python вычисляются один раз — при определении функции.
🔸 В extendList(val, list=[]) — этот list=[] сохраняется один и тот же объект списка для всех вызовов функции, где не передаётся list.
Что происходит:
list1 = extendList(10)
→ list=[] по умолчанию
→ list = [10]
→ list1 → [10]
list2 = extendList(123, [])
→ передали новый список
→ list = [123]
→ list2 → [123]
list3 = extendList('a')
→ снова использован тот же список, что и в list1
→ list = [10, 'a']
→ list3 → [10, 'a']
→ и list1 тоже теперь [10, 'a'], потому что это один и тот же объект
Вывод будет:
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']
Уже доступно! Исследование Telegram 2025 — ключевые инсайты года 
