Python: задачки и вопросы
7.51K subscribers
1.26K photos
1 video
1 file
115 links
Вопросы и задачки для подготовки к собеседованиям и прокачки навыков

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/media
Download Telegram
По умолчанию сортировка разных типов в 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 в ключе или заранее фильтровать данные.

Вариант устойчивого ключа:

𝚍𝚎𝚏 𝚔(𝚡):
𝚝𝚛𝚢:
𝚛𝚎𝚝𝚞𝚛𝚗 (𝚒𝚜𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎(𝚡, 𝚜𝚝𝚛), 𝚒𝚗𝚝(𝚡))
𝚎𝚡𝚌𝚎𝚙𝚝 𝚅𝚊𝚕𝚞𝚎𝙴𝚛𝚛𝚘𝚛:
𝚛𝚎𝚝𝚞𝚛𝚗 (𝚒𝚜𝚒𝚗𝚜𝚝𝚊𝚗𝚌𝚎(𝚡, 𝚜𝚝𝚛), 𝚏𝚕𝚘𝚊𝚝('𝚒𝚗𝚏'))
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Генератор 𝚐𝚎𝚗 создаётся как выражение: 𝚐𝚎𝚗 = ( 𝚡 * 𝚡 𝚏𝚘𝚛 𝚡 𝚒𝚗 𝚖𝚊𝚔𝚎() 𝚒𝚏 𝚡 % 𝟸 ). В этот момент 𝚖𝚊𝚔𝚎() УЖЕ вызывается — Python сразу вычисляет самый внешний итерируемый объект, чтобы создать итератор. Поэтому «build» выводится при создании генератора, ДО строки с 𝚙𝚛𝚒𝚗𝚝. Ленивыми остаются только фильтр 𝚒𝚏 𝚡 % 𝟸 и преобразование 𝚡 * 𝚡 — они применяются при итерации.

В строке 𝚙𝚛𝚒𝚗𝚝(𝚜𝚞𝚖(𝚐𝚎𝚗), 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗)) аргументы оцениваются слева направо.

🔘Сначала вызывается 𝚜𝚞𝚖(𝚐𝚎𝚗). Генератор начинает итерацию по списку из 𝚖𝚊𝚔𝚎(), применяя фильтр 𝚒𝚏 𝚡 % 𝟸 — остаются 𝟷 и 𝟹. К ним применяется 𝚡 * 𝚡 → 𝟷, 𝟿, а 𝚜𝚞𝚖 даёт 𝟷𝟶.

🔘Затем вызывается 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗). Но генератор уже исчерпан предыдущей суммой: его внутренний итератор достиг конца. Повторная попытка даёт пустую последовательность → []. При этом list обрабатывает StopIteration и ошибки не будет.

Итоговая печать выводит «𝟷𝟶 []». Поэтому верный вариант — «build» (вывелось ДО строки с 𝚙𝚛𝚒𝚗𝚝), а затем «𝟷𝟶 []».

Полезные выводы:
🔘 Генераторы «одноразовые»: один проход — и состояние на конце. Хотите повторного обхода — сохраните данные: 𝚍𝚊𝚝𝚊 = 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗) или создайте новый генератор.
🔘Самый внешний итератор (𝚖𝚊𝚔𝚎()) вычисляется немедленно при создании генератора, поэтому побочные эффекты в нём проявятся сразу. Ленивыми остаются только условия и преобразования эллементов.
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код?
Anonymous Quiz
47%
4 one
14%
2 one
40%
2 yes
0%
4 yes
2
В Python булевы значения 𝚃𝚛𝚞𝚎 и 𝙵𝚊𝚕𝚜𝚎 являются подклассами 𝚒𝚗𝚝, причём 𝚃𝚛𝚞𝚎 == 𝟷 и 𝙵𝚊𝚕𝚜𝚎 == 𝟶. Словарь считает равные ключи (с одинаковым хэшем и равенством) идентичными, поэтому при добавлении дублирующего ключа сохраняется первый вставленный ключ, но перезаписывается значение.

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

Почему так работает:
Словарь использует хэш и оператор == для определения уникальности ключей. Хэши 𝚃𝚛𝚞𝚎 и 𝟷 одинаковы (оба 1), и они равны по ==, поэтому считаются одним ключом. При коллизии ключей словарь не заменяет сам ключ — он оставляет первый вставленный (в данном случае числовой 1), но обновляет значение последним переданным ('yes' от True). Это значит, что если выведете ключи словаря через 𝚕𝚒𝚜𝚝(𝚍.𝚔𝚎𝚢𝚜()), увидите, а не [False, True].​

Практика:
🔘Избегайте смешивания булевых и числовых ключей в словарях — это приводит к неожиданным перезаписям.
🔘Проверить хэш: 𝚑𝚊𝚜𝚑(𝚃𝚛𝚞𝚎) == 𝚑𝚊𝚜𝚑(𝟷) → True, 𝚑𝚊𝚜𝚑(𝙵𝚊𝚕𝚜𝚎) == 𝚑𝚊𝚜𝚑(𝟶) → True.
🔘Если нужно использовать булевы значения как отдельные ключи, храните их в виде строк: {'True': ..., 'False': ...}.
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥2