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

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

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

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

Другие наши проекты: https://tprg.ru/media
Download Telegram
Генератор 𝚐𝚎𝚗 создаётся как выражение: 𝚐𝚎𝚗 = ( 𝚡 * 𝚡 𝚏𝚘𝚛 𝚡 𝚒𝚗 𝚖𝚊𝚔𝚎() 𝚒𝚏 𝚡 % 𝟸 ). В этот момент 𝚖𝚊𝚔𝚎() УЖЕ вызывается — Python сразу вычисляет самый внешний итерируемый объект, чтобы создать итератор. Поэтому «build» выводится при создании генератора, ДО строки с 𝚙𝚛𝚒𝚗𝚝. Ленивыми остаются только фильтр 𝚒𝚏 𝚡 % 𝟸 и преобразование 𝚡 * 𝚡 — они применяются при итерации.

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

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

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

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

Полезные выводы:
🔘 Генераторы «одноразовые»: один проход — и состояние на конце. Хотите повторного обхода — сохраните данные: 𝚍𝚊𝚝𝚊 = 𝚕𝚒𝚜𝚝(𝚐𝚎𝚗) или создайте новый генератор.
🔘Самый внешний итератор (𝚖𝚊𝚔𝚎()) вычисляется немедленно при создании генератора, поэтому побочные эффекты в нём проявятся сразу. Ленивыми остаются только условия и преобразования эллементов.
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код?
Anonymous Quiz
48%
4 one
15%
2 one
35%
2 yes
2%
4 yes
4
В 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
🔥43
Что выведет код?
Anonymous Quiz
12%
typ
7%
pyt
19%
noht
63%
htyp
👍62
Срезы в 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:]
Please open Telegram to view this post
VIEW IN TELEGRAM
4
Forwarded from Типичный программист
С кем знакомятся типичные программисты: 2D-тян или живая девушка?

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

Мы решили провести своё исследование и выяснить где и с кем сегодня знакомятся пользователи стран СНГ. Пожалуйста, пройдите наш небольшой опрос. Это поможет нашему исследованию.

Пройти опрос.
3
Что выведет код?
Anonymous Quiz
45%
True True
29%
True False
20%
False False
6%
False True
1
Оператор += для списков работает in-place (изменяет объект на месте), в отличие от обычной конкатенации +, которая создаёт новый список.

Разбор по шагам:
🔘𝚊 = создаёт список.
🔘𝚋 = 𝚊 создаёт новую ссылку на тот же список; 𝚊 и 𝚋 указывают на один объект в памяти.
🔘𝚊 += вызывает метод 𝚊.𝚎𝚡𝚝𝚎𝚗𝚍() — расширяет существующий список, добавляя элемент 3. Объект не меняется, изменяется его содержимое.
🔘Поскольку 𝚋 указывает на тот же объект, изменения видны и через 𝚋.
🔘𝚊 == 𝚋 → True (значения равны), 𝚊 𝚒𝚜 𝚋 → True (это один и тот же объект).

Сравнение с обычным +
Если бы использовали 𝚊 = 𝚊 + [3], поведение было бы другим. Создавался бы новый список 𝚊. Переменная 𝚋 продолжала бы указывать на старый список , поэтому 𝚊 == 𝚋 → False, 𝚊 𝚒𝚜 𝚋 → False.

Почему += работает in-place
Для изменяемых типов (списки, множества, словари) оператор += оптимизирован: вместо создания нового объекта он модифицирует существующий. Для неизменяемых типов (строки, кортежи, числа) += всегда создаёт новый объект. Аналогично ведёт себя *=.
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Please open Telegram to view this post
VIEW IN TELEGRAM
🗿4🤔1