ru
Feedback
Python: задачки и вопросы

Python: задачки и вопросы

Открыть в Telegram

Вопросы и задачки для подготовки к собеседованиям и прокачки навыков Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels Другие наши проекты: https://tprg.ru/media

Больше
7 131
Подписчики
-124 часа
+77 дней
Нет данных30 день
Архив постов
Сегодня попробуем новый формат: вопрос без правильного ответа. Творческий, где есть место рассуждениям вслух. Допустим, вы со
Сегодня попробуем новый формат: вопрос без правильного ответа. Творческий, где есть место рассуждениям вслух. Допустим, вы создаёте библиотеку для удобного поиска файлов и каких-то действий с ними. Например, надо найти в директории C:\logs все файлы больше 10 МБ с раcширением .log и не старше недели. Если использовать стандартные os.stat и datetime, то получается громоздко. Задача — сделать это как можно более красиво, лаконично и pythonic way. Некоторые неплохие варианты можно посмотреть в этом посте. Кстати, тоже канал по Python, который я веду лично. Свои варианты интерфейса для обхода файлов с фильтрами кидайте в комментарии. Вместе обсудим плюсы и минусы, будет такая небольшая практика на выходных.

Главный трюк этой конструкции в том, что else здесь относится не к if, а именно к циклу for. Цикл с else в Python можно читать так: для ... если цикл отработал до конца без break, то выполни ...​ Разберём код построчно: 🔘Старт цикла: 𝚏𝚘𝚛 𝚒 𝚒𝚗 𝚛𝚊𝚗𝚐𝚎(𝟹): — значения 𝚒 будут 𝟶, 𝟷, 𝟸 по очереди.​ 🔘Первая итерация: 𝚒 = 𝟶 → выполняется 𝚙𝚛𝚒𝚗𝚝(𝚒, 𝚎𝚗𝚍=' '), на экран уходит 0 .​Условие 𝚒 == 𝟷 ложно, 𝚋𝚛𝚎𝚊𝚔 не выполняется, цикл спокойно переходит к следующему значению.​ 🔘Вторая итерация: 𝚒 = 𝟷 → снова 𝚙𝚛𝚒𝚗𝚝(𝚒, 𝚎𝚗𝚍=' '), теперь на экране 0 1. Условие 𝚒 == 𝟷 становится истинным, выполняется 𝚋𝚛𝚎𝚊𝚔, и цикл немедленно прерывается изнутри, не доходя до конца диапазона.​ 🔘Что происходит с else: Блок 𝚎𝚕𝚜𝚎: 𝚙𝚛𝚒𝚗𝚝("𝚎𝚕𝚜𝚎", 𝚎𝚗𝚍=' ') выполняется только если цикл завершился «нормально» — то есть перебрал все элементы 𝚛𝚊𝚗𝚐𝚎(𝟹) без выхода через 𝚋𝚛𝚎𝚊𝚔. Здесь цикл прерывается на 𝚒 = 𝟷, поэтому 𝚎𝚕𝚜𝚎 пропускается.​ 🔘Завершение программы: После цикла всегда выполняется 𝚙𝚛𝚒𝚗𝚝("𝚍𝚘𝚗𝚎"), поэтому к уже напечатанному 0 1 добавляется done, итого вывод: 0 1 done.​ Как про это думать Полезная ментальная модель: цикл for … else работает почти как «поиск с флагом»: 🔘Если внутри цикла нашлось «что‑то особенное» и вы сделали 𝚋𝚛𝚎𝚊𝚔, 𝚎𝚕𝚜𝚎 не выполняется.​ 🔘Если вы честно прошли все элементы и так и не сделали 𝚋𝚛𝚎𝚊𝚔, тогда срабатывает 𝚎𝚕𝚜𝚎 — как ветка «ничего не нашли».

Что выведет код?
Anonymous voting

Бро, ты можешь тут реализоваться и т.д. Став частью ОТП Банка, именно ты сделаешь сильнее всю команду! Расти, учись и пробуй новое — это твой шанс создать что-то по-настоящему крутое. Присоединяйся к ребятам и делись роликом с теми, кто тоже готов к переменам 🚀

Это пример создания рекурсивного списка — структуры данных, которая ссылается сама на себя. Python позволяет создавать такие объекты благодаря механизму ссылок. Важен порядок выполнения цепочки присваиваний. В Python цепочка присваиваний a = b = c = значение выполняется так: 🔘Сначала вычисляется самое правое выражение (создаётся объект). 🔘Затем присваивания происходят слева направо для каждой цели. Для кода Матрешка = Матрешка[0] = ['Матрешка'] выполнение идёт так Шаг 1: Вычисляется правая часть Создаётся список ['Матрешка'] — один объект в памяти Шаг 2: Первое присваивание (слева) Матрешка = ['Матрешка'] — переменная Матрешка получает ссылку на этот список Шаг 3: Второе присваивание Матрешка[0] = ['Матрешка'] — теперь Матрешка уже определена (из шага 2!), и мы можем обратиться к её первому элементу. Первый элемент (строка 'Матрешка') заменяется ссылкой на весь тот же список. Ключевой момент Когда выполняется Матрешка[0] = ..., переменная Матрешка уже существует — она была создана на предыдущем шаге цепочки. Поэтому мы можем обратиться к её элементу и заменить строку 'Матрешка' на ссылку на весь список. Результат: список, который содержит сам себя в качестве первого элемента — рекурсивная структура [[...]]. Подводные камни: 🔘Такие структуры нельзя корректно сериализовать в JSON. 🔘Наивное копирование создаст проблемы — нужен 𝚌𝚘𝚙𝚢.𝚍𝚎𝚎𝚙𝚌𝚘𝚙𝚢 с обработкой циклов. 🔘Обход без проверки на посещённые узлы приведёт к бесконечной рекурсии.

Что выведет код?
Anonymous voting

photo content

Уже сегодня через несколько часов начнется конференция «Проектная исповедь» — о том, как жить, работать и ошибаться в мире ди
Уже сегодня через несколько часов начнется конференция «Проектная исповедь» — о том, как жить, работать и ошибаться в мире дилемм. Всего вас ждет 8 выступлений, кратко расскажем, что к чему 12:10 — Сергей Кожемякин поведает "Исповедь контрол‑фрика: как подчинить тревожность и использовать её в работе" 12:35 — Анна Аксенова поделится, как "Создать из хаоса порядок, или как сверить несверяемое" 13:00 — Алексей Мостовщиков и Андрей Лупий дадут инструкцию по применению GR в ИТ 13:25 — Яна Федорова расскажет, как "Промолчать ради гармонии или говорить о проблемах" 13:50 — Александр Ряховский поможет найти баланс контроля и вдохновения на выступлении "Искусство управлять невозможным" 14:15 — Дмитрий Урузгалиев построит "Мосты вместо стен: как соединить работу и жизнь, не сгорев на границе" 14:40 — Алексей Шершнев объяснит, "Что на самом деле убивает ИТ‑проекты" 15:05 — Иван Москвин покажет, как "Кастомизировать продукт под каждого или делать универсальное решение" Конференция бесплатная, но надо зарегистрироваться. Сделать это можно на красивом лендинге: https://tprg.ru/KkLb Это #партнёрский пост

Оператор * в множественном присваивании собирает «остатки» последовательности в список. Он работает как жадный захват всех элементов между фиксированными переменными. Разбор по шагам: 🔘𝚡 = [𝟷, 𝟸, 𝟹, 𝟺, 𝟻] # список из 5 элементов 🔘𝚊, *𝚋, 𝚌 = 𝚡 # распаковка с остатком: a берёт первый элемент: a = 1, c берёт последний элемент: c = 5 *b собирает всё, что между: b = [2, 3, 4] 🔘𝚙𝚛𝚒𝚗𝚝(𝚕𝚎𝚗(𝚋)) # 3 Как работает распаковка 🔘Переменные без * получают ровно один элемент. 🔘Переменная с * захватывает всё оставшееся (может быть пустым списком). 🔘* можно использовать только один раз в присваивании. Примеры разных случаев 𝚡 = [𝟷, 𝟸] *𝚊, 𝚋 = 𝚡 # a = 1, b = 2 𝚢 = [𝟷] *𝚌, 𝚍 = 𝚢 # c = [ ], d = 1 (остаток пустой!) 𝚣 = [𝟷, 𝟸, 𝟹] 𝚎, *𝚏 = 𝚣 # e = 1, f = [2, 3] Зачем нужно такое поведение 🔘Элегантно обрабатывать последовательности переменной длины. 🔘Частый паттерн: 𝚏𝚒𝚛𝚜𝚝, *𝚛𝚎𝚜𝚝 = 𝚕𝚒𝚜𝚝 для разделения головы и хвоста. 🔘Работает с любыми итерируемыми объектами: списками, кортежами, строками. Подводные камни 🔘Если элементов меньше, чем фиксированных переменных, получите ValueError. 🔘* всегда создаёт список, даже если элементов нет. 🔘Можно игнорировать остаток через : 𝚊, *, 𝚋 = [𝟷, 𝟸, 𝟹, 𝟺] → игнорируем середину.

Что выведет код?
Anonymous voting

photo content

Оператор += для списков работает in-place (изменяет объект на месте), в отличие от обычной конкатенации +, которая создаёт новый список. Разбор по шагам: 🔘𝚊 = создаёт список. 🔘𝚋 = 𝚊 создаёт новую ссылку на тот же список; 𝚊 и 𝚋 указывают на один объект в памяти. 🔘𝚊 += вызывает метод 𝚊.𝚎𝚡𝚝𝚎𝚗𝚍() — расширяет существующий список, добавляя элемент 3. Объект не меняется, изменяется его содержимое. 🔘Поскольку 𝚋 указывает на тот же объект, изменения видны и через 𝚋. 🔘𝚊 == 𝚋 → True (значения равны), 𝚊 𝚒𝚜 𝚋 → True (это один и тот же объект). Сравнение с обычным + Если бы использовали 𝚊 = 𝚊 + [3], поведение было бы другим. Создавался бы новый список 𝚊. Переменная 𝚋 продолжала бы указывать на старый список , поэтому 𝚊 == 𝚋 → False, 𝚊 𝚒𝚜 𝚋 → False. Почему += работает in-place Для изменяемых типов (списки, множества, словари) оператор += оптимизирован: вместо создания нового объекта он модифицирует существующий. Для неизменяемых типов (строки, кортежи, числа) += всегда создаёт новый объект. Аналогично ведёт себя *=.

Что выведет код?
Anonymous voting

photo content

С кем знакомятся типичные программисты: 2D-тян или живая девушка? Согласно недавним исследованиям Vantage Point Counseling Se
С кем знакомятся типичные программисты: 2D-тян или живая девушка? Согласно недавним исследованиям Vantage Point Counseling Services, треть американцев хотя бы раз состояла в романтических отношениях с ИИ. Появилось даже приложение Loverse для виртуальных знакомств, где вместо реальных людей роль партнёров выполняют чат-боты с искусственным интеллектом. Мы решили провести своё исследование и выяснить где и с кем сегодня знакомятся пользователи стран СНГ. Пожалуйста, пройдите наш небольшой опрос. Это поможет нашему исследованию. Пройти опрос.

Срезы в Python обрабатываются последовательно слева направо: сначала применяется первый срез к строке, результат становится новой строкой, затем к ней применяется следующий срез. Разбор по шагам: 🔘Исходная строка: 𝚜 = "𝚙𝚢𝚝𝚑𝚘𝚗". 🔘Первый срез 𝚜[::−𝟷] разворачивает строку задом наперёд → "𝚗𝚘𝚑𝚝𝚢𝚙". 🔘Второй срез [𝟸:] берёт всё начиная с индекса 2 (третий символ) до конца из развёрнутой строки → "𝚑𝚝𝚢𝚙". 🔘Итоговый результат: "𝚑𝚝𝚢𝚙". Почему это работает именно так: Срезы создают новые объекты (строки неизменяемы), и каждый срез применяется к результату предыдущего. После разворота строка становится "𝚗𝚘𝚑𝚝𝚢𝚙" (индексы: n=0, o=1, h=2, t=3, y=4, p=5), и [𝟸:] берёт символы начиная с индекса 2, то есть "𝚑𝚝𝚢𝚙". Практика и сравнение: 🔘𝚜[::−𝟷][𝟸:] ≠ 𝚜[𝟸::−𝟷]: первое разворачивает всю строку, затем обрезает; второе берёт срез с индекса 2 исходной строки и идёт назад. 🔘Пример: для "𝚙𝚢𝚝𝚑𝚘𝚗" срез 𝚜[𝟸::−𝟷] начинает с 't' (индекс 2) и движется назад → "𝚝𝚢𝚙". 🔘Срез 𝚜[::−𝟷][𝟸:] сначала делает "𝚗𝚘𝚑𝚝𝚢𝚙", затем [𝟸:] берёт с позиции 2 → "𝚑𝚝𝚢𝚙". Подводные камни: 🔘Цепочки срезов читаются слева направо, как вызовы методов; каждый срез возвращает новый объект. 🔘Отрицательный шаг меняет направление обхода, но не меняет порядок применения срезов в цепочке. 🔘Для сложных операций лучше разбивать на отдельные переменные для читаемости: сначала reversed_s = s[::-1], затем result = reversed_s[2:]

Что выведет код?
Anonymous voting

photo content

В Python булевы значения 𝚃𝚛𝚞𝚎 и 𝙵𝚊𝚕𝚜𝚎 являются подклассами 𝚒𝚗𝚝, причём 𝚃𝚛𝚞𝚎 == 𝟷 и 𝙵𝚊𝚕𝚜𝚎 == 𝟶. Словарь считает равные ключи (с одинаковым хэшем и равенством) идентичными, поэтому при добавлении дублирующего ключа сохраняется первый вставленный ключ, но перезаписывается значение. Разбор по шагам: 🔘𝟶: '𝚣𝚎𝚛𝚘' — добавляется пара {𝟶: '𝚣𝚎𝚛𝚘'}. 🔘𝟷: '𝚘𝚗𝚎' — добавляется пара {𝟷: '𝚘𝚗𝚎'}. 🔘𝚃𝚛𝚞𝚎: '𝚢𝚎𝚜' — так как 𝚃𝚛𝚞𝚎 == 𝟷 и хэши совпадают, словарь считает это тем же ключом; значение перезаписывается на 'yes', но ключ остаётся 𝟷 (первый вставленный) → {𝟶: '𝚣𝚎𝚛𝚘', 𝟷: '𝚢𝚎𝚜'}. 🔘𝙵𝚊𝚕𝚜𝚎: '𝚗𝚘' — аналогично, 𝙵𝚊𝚕𝚜𝚎 == 𝟶, значение перезаписывается, ключ остаётся 𝟶 → {𝟶: '𝚗𝚘', 𝟷: '𝚢𝚎𝚜'}. 🔘Финальный словарь: {𝟶: '𝚗𝚘', 𝟷: '𝚢𝚎𝚜'} — два уникальных ключа, поэтому 𝚕𝚎𝚗(𝚍) = 𝟸. 🔘𝚍 обращается к ключу 1, который в словаре хранится как числовой ключ 1 (хотя значение было перезаписано булевым True на 'yes'), возвращается 'yes'.​ Почему так работает: Словарь использует хэш и оператор == для определения уникальности ключей. Хэши 𝚃𝚛𝚞𝚎 и 𝟷 одинаковы (оба 1), и они равны по ==, поэтому считаются одним ключом. При коллизии ключей словарь не заменяет сам ключ — он оставляет первый вставленный (в данном случае числовой 1), но обновляет значение последним переданным ('yes' от True). Это значит, что если выведете ключи словаря через 𝚕𝚒𝚜𝚝(𝚍.𝚔𝚎𝚢𝚜()), увидите, а не [False, True].​ Практика: 🔘Избегайте смешивания булевых и числовых ключей в словарях — это приводит к неожиданным перезаписям. 🔘Проверить хэш: 𝚑𝚊𝚜𝚑(𝚃𝚛𝚞𝚎) == 𝚑𝚊𝚜𝚑(𝟷) → True, 𝚑𝚊𝚜𝚑(𝙵𝚊𝚕𝚜𝚎) == 𝚑𝚊𝚜𝚑(𝟶) → True. 🔘Если нужно использовать булевы значения как отдельные ключи, храните их в виде строк: {'True': ..., 'False': ...}.