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

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

Відкрити в Telegram

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

Показати більше
6 963
Підписники
+124 години
-67 днів
-6130 день
Архів дописів
С кем знакомятся типичные программисты: 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': ...}.

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

Генератор 𝚐𝚎𝚗 создаётся как выражение: 𝚐𝚎𝚗 = ( 𝚡 * 𝚡 𝚏𝚘𝚛 𝚡 𝚒𝚗 𝚖𝚊𝚔𝚎() 𝚒𝚏 𝚡 % 𝟸 ). В этот момент 𝚖𝚊𝚔𝚎() ЕЩЁ НЕ вызывается — генератор ленивый и откладывает вычисления до итерации. В строке 𝚙𝚛𝚒𝚗𝚝(𝚜𝚞𝚖(𝚐𝚎𝚗), 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗)) аргументы оцениваются слева направо. 🔘Сначала вызывается 𝚜𝚞𝚖(𝚐𝚎𝚗). При первой итерации генератора срабатывает 𝚖𝚊𝚔𝚎(), печатается «build», и генератор начинает перебирать список с фильтром 𝚒𝚏 𝚡 % 𝟸 — остаются 𝟷 и 𝟹. К ним применяется 𝚡 * 𝚡 → 𝟷, 𝟿, а 𝚜𝚞𝚖 даёт 𝟷𝟶.​ 🔘Затем вызывается 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗). Но генератор уже исчерпан предыдущей суммой: его внутренний итератор достиг конца. Повторная попытка даёт пустую последовательность → []. Итоговая печать выводит «build» (из 𝚖𝚊𝚔𝚎), затем «𝟷𝟶 []». Поэтому верный вариант — «build» и «𝟷𝟶 []» на одной строке параметров 𝚙𝚛𝚒𝚗𝚝, а список пустой из‑за одноразовости генератора. Полезные выводы: 🔘 Генераторы «одноразовые»: один проход — и состояние на конце. Хотите повторного обхода — сохраните данные: 𝚍𝚊𝚝𝚊 = 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗) или создайте новый генератор. 🔘Вложенные побочные эффекты (как 𝚙𝚛𝚒𝚗𝚝 внутри 𝚖𝚊𝚔𝚎) проявятся в момент первой итерации, а не при создании генератора.

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

photo content

По умолчанию сортировка разных типов в Python 3 невозможна, но параметр key позволяет задать нормализацию данных. Ключ — кортеж (isinstance(x, str), int(x)): сначала сортируем по флагу «x — строка?» (False < True, значит числа идут раньше строк), затем по числовому значению int(x). Разбор по шагам: 🔘Для 1 ключ (False, 1), для 2 — (False, 2). Для '3' — (True, 3), для '10' — (True, 10), для '20' — (True, 20). 🔘Сначала все элементы с False: 1, 2; затем True: '3', '10', '20'. Внутри групп сравнение по второму элементу ключа, то есть по числу после приведения. 🔘Поэтому результат — [1, 2, '3', '10', '20']. Подводные камни: 🔘Без key будет TypeError, потому что числа и строки несравнимы. 🔘Если в данных встретится строка, не приводимая к int (например, 'x'), key упадёт с ValueError — для устойчивости можно использовать try/except в ключе или заранее фильтровать данные. Вариант устойчивого ключа: 𝚍𝚎𝚏 𝚔(𝚡): 𝚝𝚛𝚢: 𝚛𝚎𝚝𝚞𝚛𝚗 (𝚒𝚜𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎(𝚡, 𝚜𝚝𝚛), 𝚒𝚗𝚝(𝚡)) 𝚎𝚡𝚌𝚎𝚙𝚝 𝚅𝚊𝚕𝚞𝚎𝙴𝚛𝚛𝚘𝚛: 𝚛𝚎𝚝𝚞𝚛𝚗 (𝚒𝚜𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎(𝚡, 𝚜𝚝𝚛), 𝚏𝚕𝚘𝚊𝚝('𝚒𝚗𝚏'))

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

Методы 𝚔𝚎𝚢𝚜(), 𝚟𝚊𝚕𝚞𝚎𝚜(), 𝚒𝚝𝚎𝚖𝚜() возвращают не списки, а динамические представления (views) словаря, которые автоматически обновляются при изменениях в оригинальном словаре. Разбор по шагам: 🔘𝚍 = {'a': 10, 'b': 20} создаёт словарь с двумя парами. 🔘𝚔𝚎𝚢𝚜 = 𝚍.𝚔𝚎𝚢𝚜() возвращает 𝚍𝚒𝚌𝚝_𝚔𝚎𝚢𝚜(['a', 'b']) — представление ключей, отражающее текущее состояние 𝚍. 🔘𝚍['c'] = 30 добавляет новую пару; представление 𝚔𝚎𝚢𝚜 мгновенно видит три ключа, поэтому 𝚕𝚒𝚜𝚝(𝚔𝚎𝚢𝚜) даёт ['a', 'b', 'c']. 🔘𝚍.𝚙𝚘𝚙('a') удаляет ключ 'a'; представление снова обновляется, и теперь 𝚕𝚎𝚗(𝚔𝚎𝚢𝚜) возвращает 2 (остались 'b' и 'c'). Views — это не копии, а «живые» ссылки на словарь, экономящие память и время. В отличие от Python 2 (где 𝚍𝚒𝚌𝚝.𝚔𝚎𝚢𝚜() возвращал список-копию), в Python 3 представления всегда динамичны. Если бы код использовал 𝚕𝚒𝚜𝚝(𝚍.𝚔𝚎𝚢𝚜()) в начале, то 𝚘𝚕𝚍_𝚔𝚎𝚢𝚜 = 𝚕𝚒𝚜𝚝(𝚍.𝚔𝚎𝚢𝚜()), добавление 'c' не повлияло бы на 𝚘𝚕𝚍_𝚔𝚎𝚢𝚜 — оно осталось бы ['a', 'b'].

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

photo content

В Python значения аргументов по умолчанию вычисляются один раз — при определении функции, а не при каждом вызове. Если использовать изменяемый объект (например, список) как аргумент по умолчанию, все вызовы функции без передачи значения будут работать с одним и тем же объектом. В этом примере список 𝚡 создаётся при определении 𝚏𝚞𝚗, и каждый вызов 𝚏𝚞𝚗() добавляет в него единицу. Поэтому после первого вызова выводится [𝟷], а после второго уже [𝟷, 𝟷]. Такой эффект ловит многих: кажется, будто 𝚡 — новый пустой список при каждом вызове, но на деле это один и тот же, постоянно растущий список.​ Чтобы избежать такого поведения, используйте 𝙽𝚘𝚗𝚎 как значение по умолчанию — тогда новый список создаётся при каждом вызове: 𝚍𝚎𝚏 𝚏𝚞𝚗(𝚡=𝙽𝚘𝚗𝚎):   𝚒𝚏 𝚡 𝚒𝚜 𝙽𝚘𝚗𝚎:     𝚡 = [ ]   𝚡.𝚊𝚙𝚙𝚎𝚗𝚍(𝟷)   𝚛𝚎𝚝𝚞𝚛𝚗 𝚡 Теперь каждый раз будет новый список: [𝟷] — поведение ожидаемое и безопасное для задач, где нужны независимые коллекции.​ Эта особенность касается любых изменяемых типов: списков, словарей и даже пользовательских объектов. Полезно обратить на это внимание при проектировании функций‑инструментов и обработчиков.

Что выведет код? Перевод на новую строку и пробелы не учитываем, вопрос про списки.
Anonymous voting

photo content

Метод умножения списка создаёт несколько ссылок на один и тот же внутренний список, а не независимые копии, поэтому все строки в 𝚖𝚊𝚝𝚛𝚒𝚡 указывают на один объект. Изменение элемента 𝚖𝚊𝚝𝚛𝚒𝚡 фактически меняет общий вложенный список, и та же единица появляется в каждой строке. Проверить это можно по 𝚒𝚍: [𝚒𝚍(𝚛𝚘𝚠) 𝚏𝚘𝚛 𝚛𝚘𝚠 𝚒𝚗 𝚖𝚊𝚝𝚛𝚒𝚡] даёт одинаковые значения. Как правильно: создавать каждую строку заново, например с генератором списков: 𝚖𝚊𝚝𝚛𝚒𝚡 = [[𝟶 𝚏𝚘𝚛 _ 𝚒𝚗 𝚛𝚊𝚗𝚐𝚎(𝟹)] 𝚏𝚘𝚛 _ 𝚒𝚗 𝚛𝚊𝚗𝚐𝚎(𝟹)] Теперь каждая строка независима, и изменение одной не затрагивает остальные. Для копирования уже созданной матрицы используйте копирование по элементам, например 𝚕𝚒𝚜𝚝(𝚖𝚊𝚙(𝚕𝚒𝚜𝚝, 𝚖𝚊𝚝𝚛𝚒𝚡)) или 𝚍𝚎𝚎𝚙𝚌𝚘𝚙𝚢 из модуля 𝚌𝚘𝚙𝚢, если внутри есть вложенные структуры.