🧰 Code Cleanup
На первый взгляд — обычный код.
Но именно так пишут на автомате… и теряют читаемость.
❌ Плохой код
✅ Улучшенный код
💥 Объяснение
Работает и так, и так.
Но есть нюанс.
👉 В первом варианте ты заставляешь мозг держать:
🔷 временный список
🔷 цикл
🔷 условие
🔷 мутацию (
👉 Во втором — всё выражено как одна мысль:
«возьми имена пользователей старше 18»
И это ключевое отличие.
🧠 Где здесь ловушка
Многие думают:
🔷 «list comprehension — это просто короче»
На самом деле:
🔷 Это декларативный стиль, а не просто синтаксический сахар
Ты описываешь *что хочешь получить*, а не *как это собирать по шагам*.
⚠️ Но не переусердствуй
Вот так — уже плохо:
Становится сложно читать.
🐍Вопросы с собесов -> ProstoPython
На первый взгляд — обычный код.
Но именно так пишут на автомате… и теряют читаемость.
❌ Плохой код
users = [
{"name": "Alice", "age": 17},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 16},
]
result = []
for u in users:
if u["age"] >= 18:
result.append(u["name"])
print(result)
✅ Улучшенный код
result = [user["name"] for user in users if user["age"] >= 18]
💥 Объяснение
Работает и так, и так.
Но есть нюанс.
👉 В первом варианте ты заставляешь мозг держать:
🔷 временный список
🔷 цикл
🔷 условие
🔷 мутацию (
append)👉 Во втором — всё выражено как одна мысль:
«возьми имена пользователей старше 18»
И это ключевое отличие.
🧠 Где здесь ловушка
Многие думают:
🔷 «list comprehension — это просто короче»
На самом деле:
🔷 Это декларативный стиль, а не просто синтаксический сахар
Ты описываешь *что хочешь получить*, а не *как это собирать по шагам*.
⚠️ Но не переусердствуй
Вот так — уже плохо:
result = [u["name"].upper() for u in users if u["age"] >= 18 and u["name"].startswith("A")]Становится сложно читать.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
UDP (User Datagram Protocol) — транспортный протокол для передачи данных без установления соединения.
Особенности
🔹 нет установки соединения (connectionless)
🔹 нет гарантии доставки
🔹 нет порядка доставки
🔹 минимальные накладные расходы → высокая скорость
Когда используется
🔹 стриминг (видео/аудио)
🔹 онлайн-игры
🔹 DNS-запросы
Итог: UDP — быстрый, но ненадёжный протокол передачи данных без подтверждений и контроля доставки.
🐍Вопросы с собесов -> ProstoPython
Особенности
🔹 нет установки соединения (connectionless)
🔹 нет гарантии доставки
🔹 нет порядка доставки
🔹 минимальные накладные расходы → высокая скорость
Когда используется
🔹 стриминг (видео/аудио)
🔹 онлайн-игры
🔹 DNS-запросы
Итог: UDP — быстрый, но ненадёжный протокол передачи данных без подтверждений и контроля доставки.
🐍Вопросы с собесов -> ProstoPython
🔥3
❌ Rookie Mistakes
На первый взгляд — код абсолютно безопасный.
Но именно здесь многие ловят странные баги.
❌ Пример с ошибкой
🤯 Ожидание
💥 Реальность
🧠 Почему это ошибка
На первый взгляд кажется:
data={} создаётся заново при каждом вызове.
Но…
👉 Значение по умолчанию создаётся один раз
👉 И это один и тот же словарь
Ты не создаёшь новый dict — ты каждый раз дописываешь в старый
⚠️ Именно здесь чаще всего ошибаются
Многие думают:
«Функция вызвалась → значит всё внутри новое»
На самом деле:
Дефолтные аргументы живут между вызовами
✅ Исправленный вариант
Теперь каждый вызов создаёт новый словарь.
⚡️ Краткий вывод
Если видишь в аргументах:
👉 это потенциальный баг
🐍Вопросы с собесов -> ProstoPython
На первый взгляд — код абсолютно безопасный.
Но именно здесь многие ловят странные баги.
❌ Пример с ошибкой
def add_user(name, data={}):
data[name] = len(name)
return data
print(add_user("Alice"))
print(add_user("Bob"))
print(add_user("Charlie"))🤯 Ожидание
{'Alice': 5}
{'Bob': 3}
{'Charlie': 7}💥 Реальность
{'Alice': 5}
{'Alice': 5, 'Bob': 3}
{'Alice': 5, 'Bob': 3, 'Charlie': 7}🧠 Почему это ошибка
На первый взгляд кажется:
data={} создаётся заново при каждом вызове.
Но…
👉 Значение по умолчанию создаётся один раз
👉 И это один и тот же словарь
Ты не создаёшь новый dict — ты каждый раз дописываешь в старый
⚠️ Именно здесь чаще всего ошибаются
Многие думают:
«Функция вызвалась → значит всё внутри новое»
На самом деле:
Дефолтные аргументы живут между вызовами
✅ Исправленный вариант
def add_user(name, data=None):
if data is None:
data = {}
data[name] = len(name)
return data
Теперь каждый вызов создаёт новый словарь.
⚡️ Краткий вывод
Если видишь в аргументах:
{} / [] / set()👉 это потенциальный баг
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
🧩 Code Cleanup
itertools — перестань писать вложенные циклы руками
Типичный код когда нужно перебрать все пары:
Работает. Но две вложенности только ради декартова произведения — многовато.
После:
Одна строка. Читается как задача — "произведение цветов и размеров".
🐍Вопросы с собесов -> ProstoPython
itertools — перестань писать вложенные циклы руками
Типичный код когда нужно перебрать все пары:
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
result = []
for color in colors:
for size in sizes:
result.append((color, size))
Работает. Но две вложенности только ради декартова произведения — многовато.
После:
from itertools import product
result = list(product(colors, sizes))
# [('red','S'),('red','M'),('red','L'),('blue','S'),('blue','M'),('blue','L')]
Одна строка. Читается как задача — "произведение цветов и размеров".
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
❌ Rookie Mistakes
Не сравнивай float через ==
Код который ломается в самый неожиданный момент:
Выведет "не равно". Всегда.
Числа с плавающей точкой хранятся в бинарном виде — и большинство десятичных дробей не представимы точно. 0.1 в памяти это не ровно 0.1 — это ближайшее представимое число.
🐍Вопросы с собесов -> ProstoPython
Не сравнивай float через ==
Код который ломается в самый неожиданный момент:
total = 0.1 + 0.2
if total == 0.3:
print("равно")
else:
print("не равно")
Выведет "не равно". Всегда.
print(0.1 + 0.2) # 0.30000000000000004
Числа с плавающей точкой хранятся в бинарном виде — и большинство десятичных дробей не представимы точно. 0.1 в памяти это не ровно 0.1 — это ближайшее представимое число.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍3
В множество (set) можно помещать только hashable (хешируемые) объекты.
Требования
🔹 объект имеет
🔹 объект неизменяемый (immutable)
🔹 корректно реализует
Можно
🔹
🔹
🔹
Нельзя
🔹
🔹
🔹
(они изменяемые → нет стабильного хеша)
🐍Вопросы с собесов -> ProstoPython
Требования
🔹 объект имеет
__hash__()🔹 объект неизменяемый (immutable)
🔹 корректно реализует
__eq__()Можно
🔹
int, float, str, bool🔹
tuple (если внутри тоже hashable)🔹
frozensetНельзя
🔹
list🔹
dict🔹
set(они изменяемые → нет стабильного хеша)
🐍Вопросы с собесов -> ProstoPython
🔥4
🧰 Code Cleanup
На первый взгляд — аккуратный код.
Но в нём есть дублирование, которое замедляет чтение.
❌ Плохой код
✅ Улучшенный код
💥 Объяснение
В первом варианте происходит лишнее:
👉 Ты сначала проверяешь наличие ключа
👉 Потом сразу используешь его же
Это дублирование логики.
🐍Вопросы с собесов -> ProstoPython
На первый взгляд — аккуратный код.
Но в нём есть дублирование, которое замедляет чтение.
❌ Плохой код
def get_active_users(users):
result = []
for user in users:
if "is_active" in user:
if user["is_active"]:
result.append(user["name"])
return result
✅ Улучшенный код
def get_active_users(users):
return [user["name"] for user in users if user.get("is_active")]
💥 Объяснение
В первом варианте происходит лишнее:
👉 Ты сначала проверяешь наличие ключа
👉 Потом сразу используешь его же
Это дублирование логики.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🔥4
🧠 Interview Thinking
Классическая задача.
Но валятся здесь не из-за кода — а из-за мышления.
📌 Задача
Дана строка:
Нужно вернуть индекс первого уникального символа.
Если нет — вернуть
👶 Как думает junior
На первый взгляд — логично.
👉 Проверяем каждый символ
👉 Если встречается 1 раз — возвращаем индекс
💥 Проблема
Метод
А он вызывается внутри цикла.
👉 Итог: O(n²)
На маленьких строках — ок
На больших — просадка
🧠 Как думает сильный кандидат
🚀 Что изменилось
👉 Сначала считаем частоты → O(n)
👉 Потом один проход → O(n)
Итого: O(n)
⚠️ Но дело не только в оптимизации
Сильный кандидат:
🔷 сразу проговаривает сложность
🔷 замечает повторные операции
🔷ищет способ вынести их из цикла
🎯 Что хочет интервьюер
Не просто решение.
А чтобы ты сказал:
«Здесь есть повторный подсчёт.
Я могу вынести его в отдельную структуру»
🐍Вопросы с собесов -> ProstoPython
Классическая задача.
Но валятся здесь не из-за кода — а из-за мышления.
📌 Задача
Дана строка:
s = "leetcode"
Нужно вернуть индекс первого уникального символа.
Если нет — вернуть
-1.👶 Как думает junior
def first_unique(s):
for i in range(len(s)):
if s.count(s[i]) == 1:
return i
return -1
На первый взгляд — логично.
👉 Проверяем каждый символ
👉 Если встречается 1 раз — возвращаем индекс
💥 Проблема
Метод
count() — это O(n)А он вызывается внутри цикла.
👉 Итог: O(n²)
На маленьких строках — ок
На больших — просадка
🧠 Как думает сильный кандидат
from collections import Counter
def first_unique(s):
freq = Counter(s)
for i, char in enumerate(s):
if freq[char] == 1:
return i
return -1
🚀 Что изменилось
👉 Сначала считаем частоты → O(n)
👉 Потом один проход → O(n)
Итого: O(n)
⚠️ Но дело не только в оптимизации
Сильный кандидат:
🔷 сразу проговаривает сложность
🔷 замечает повторные операции
🔷ищет способ вынести их из цикла
🎯 Что хочет интервьюер
Не просто решение.
А чтобы ты сказал:
«Здесь есть повторный подсчёт.
Я могу вынести его в отдельную структуру»
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🔥3
📈 From O(n²) to O(n)
Задача простая.
Но именно здесь многие застревают в brute force.
📌 Задача
Дан массив чисел и число
Нужно найти два индекса, сумма элементов по которым равна
Ответ:
❌ Наивное решение (brute force)
💥 Проблема
Два вложенных цикла:
👉 O(n²)
На маленьких массивах — нормально
На больших — боль
🧠 Ключевой вопрос
На первый взгляд кажется:
«Ну а как иначе? Надо же проверить все пары»
Но…
👉 А если мы будем помнить, что уже видели?
✅ Оптимизированное решение
🚀 Что произошло
Мы заменили:
👉 «перебирать все пары»
на
👉 «проверять, встречали ли нужное значение раньше»
📉 Сложность
Один проход по массиву → O(n)
Поиск в словаре → O(1)
Итого: O(n)
⚠️ Где часто ошибаются
❌ Сначала добавляют в
→ ловят кейс, где элемент используется дважды
Правильно:
👉 сначала проверка
👉 потом добавление
🐍Вопросы с собесов -> ProstoPython
Задача простая.
Но именно здесь многие застревают в brute force.
📌 Задача
Дан массив чисел и число
target.Нужно найти два индекса, сумма элементов по которым равна
target.nums = [2, 7, 11, 15]
target = 9
Ответ:
[0, 1]❌ Наивное решение (brute force)
def two_sum(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
💥 Проблема
Два вложенных цикла:
👉 O(n²)
На маленьких массивах — нормально
На больших — боль
🧠 Ключевой вопрос
На первый взгляд кажется:
«Ну а как иначе? Надо же проверить все пары»
Но…
👉 А если мы будем помнить, что уже видели?
✅ Оптимизированное решение
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
🚀 Что произошло
Мы заменили:
👉 «перебирать все пары»
на
👉 «проверять, встречали ли нужное значение раньше»
📉 Сложность
Один проход по массиву → O(n)
Поиск в словаре → O(1)
Итого: O(n)
⚠️ Где часто ошибаются
❌ Сначала добавляют в
seen, потом проверяют→ ловят кейс, где элемент используется дважды
Правильно:
👉 сначала проверка
👉 потом добавление
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍3
Попробуйте ответить без запуска, что выведет код, разбор будет через 2 часа
🐍Вопросы с собесов -> ProstoPython
🐍Вопросы с собесов -> ProstoPython
👍4
Что выведет код выше?
Anonymous Poll
18%
[1, 2, 3] [1, 2, 3, 4]
73%
[1, 2, 3, 4] [1, 2, 3, 4]
9%
[1, 2, 3] [4]
0%
Ошибка
✅ Правильный ответ:
[1, 2, 3, 4]
[1, 2, 3, 4]
💥 Разбор
На первый взгляд кажется:
data += [4] создаёт новый список
Но это не так.
🧠 Что происходит на самом деле
Для списков:
data += [4]
👉 это мутация (аналог extend)
👉 объект изменяется на месте
А data и lst — это одна и та же ссылка.
⚠️ Где ловушка
Многие думают:
+= всегда создаёт новый объект
Но в Python:
для list → мутация
для tuple, str → новый объект
Один и тот же оператор — разное поведение.
🐍Вопросы с собесов -> ProstoPython
[1, 2, 3, 4]
[1, 2, 3, 4]
💥 Разбор
На первый взгляд кажется:
data += [4] создаёт новый список
Но это не так.
🧠 Что происходит на самом деле
Для списков:
data += [4]
👉 это мутация (аналог extend)
👉 объект изменяется на месте
А data и lst — это одна и та же ссылка.
⚠️ Где ловушка
Многие думают:
+= всегда создаёт новый объект
Но в Python:
для list → мутация
для tuple, str → новый объект
Один и тот же оператор — разное поведение.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍3
🧰 Code Cleanup
На первый взгляд — нормальный код.
Но в нём скрытая неэффективность и шум.
❌ Плохой код
✅ Улучшенный код
💥 Объяснение
В первом варианте:
👉 дважды обращаешься к
👉 руками обрабатываешь инициализацию
Код работает, но перегружен лишними действиями.
🧠 Что здесь неочевидно
Многие думают:
«Ну это же стандартный паттерн»
На самом деле:
ты берёшь на себя работу, которую уже решил Python
⚠️ Где часто ошибаются
Пишут так «по привычке»:
Хотя это почти всегда можно упростить.
⚡️ Маленькое правило
👉 Если собираешь значения в группы → смотри в сторону
👉 Убирай повторные обращения к одним и тем же данным
🐍Вопросы с собесов -> ProstoPython
На первый взгляд — нормальный код.
Но в нём скрытая неэффективность и шум.
❌ Плохой код
def group_by_type(items):
result = {}
for item in items:
if item["type"] not in result:
result[item["type"]] = []
result[item["type"]].append(item)
return result
✅ Улучшенный код
from collections import defaultdict
def group_by_type(items):
result = defaultdict(list)
for item in items:
result[item["type"]].append(item)
return result
💥 Объяснение
В первом варианте:
👉 дважды обращаешься к
item["type"]👉 руками обрабатываешь инициализацию
Код работает, но перегружен лишними действиями.
🧠 Что здесь неочевидно
Многие думают:
«Ну это же стандартный паттерн»
На самом деле:
ты берёшь на себя работу, которую уже решил Python
⚠️ Где часто ошибаются
Пишут так «по привычке»:
if key not in dict:
dict[key] = []
Хотя это почти всегда можно упростить.
⚡️ Маленькое правило
👉 Если собираешь значения в группы → смотри в сторону
defaultdict👉 Убирай повторные обращения к одним и тем же данным
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
⏱️ Big O Breakdown
Какая сложность?
A) O(n)
B) O(n²)
C) O(n · m)
D) Зависит от формы матрицы
Правильный ответ:A — O(n)
Разбор
Глаз видит два вложенных цикла и автоматически кричит «O(n²)!». Это рефлекс, и он часто врёт.
Сложность считается не по количеству циклов, а по числу итераций относительно размера входа.
Здесь внутренний пробегает по элементам строки. А внешний — по строкам. В сумме мы касаемся каждого элемента ровно один раз.
Если всего элементов — мы делаем шагов. Это O(n).
🐍Вопросы с собесов -> ProstoPython
def process(matrix):
result = []
for row in matrix:
for val in row:
result.append(val)
return result
matrix — это список из n элементов суммарно (например, 100 чисел, разбитых на строки разной длины).Какая сложность?
A) O(n)
B) O(n²)
C) O(n · m)
D) Зависит от формы матрицы
Правильный ответ:
Разбор
Сложность считается не по количеству циклов, а по числу итераций относительно размера входа.
Здесь внутренний
for val in rowЕсли всего элементов
nn🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🔥4
📈 From O(n·k) to O(n)
Задача
Дан массив и число
Наивное решение — O(n·k)
Чисто, читаемо, проходит на маленьких данных.
Проблема: для каждого из
При
Оптимизация — O(n) через deque
Идея: хранить в очереди индексы кандидатов на максимум. Поддерживать в ней убывающий порядок значений.
Почему это O(n), а не O(n·k)?
На первый взгляд внутри
На самом деле каждый элемент попадает в очередь и выпадает из неё ровно один раз за всю работу алгоритма. Сумма всех итераций внутренних
Это называется амортизированный анализ: смотрим не на худший шаг, а на суммарную работу.
🐍Вопросы с собесов -> ProstoPython
Задача
Дан массив и число
k. Для каждого окна длины k найти максимум.nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3
→ [3, 3, 5, 5, 6, 7]
Наивное решение — O(n·k)
def max_sliding(nums, k):
return [max(nums[i:i+k]) for i in range(len(nums) - k + 1)]
Чисто, читаемо, проходит на маленьких данных.
Проблема: для каждого из
n окон вызываем max(), который проходит по k элементам. Итого — O(n·k).При
n = 10⁶ и k = 10⁵ это уже 10¹¹ операций. Тесты упадут по таймауту.Оптимизация — O(n) через deque
Идея: хранить в очереди индексы кандидатов на максимум. Поддерживать в ней убывающий порядок значений.
from collections import deque
def max_sliding(nums, k):
dq = deque() # индексы, значения по ним убывают
result = []
for i, n in enumerate(nums):
# выбрасываем индексы, вышедшие за окно
while dq and dq[0] <= i - k:
dq.popleft()
# выбрасываем всё, что меньше текущего — они никогда не станут максимумом
while dq and nums[dq[-1]] < n:
dq.pop()
dq.append(i)
if i >= k - 1:
result.append(nums[dq[0]])
return result
Почему это O(n), а не O(n·k)?
На первый взгляд внутри
for есть два while — кажется, что снова вложенность.На самом деле каждый элемент попадает в очередь и выпадает из неё ровно один раз за всю работу алгоритма. Сумма всех итераций внутренних
while — не больше 2n.Это называется амортизированный анализ: смотрим не на худший шаг, а на суммарную работу.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🔥3
Новая рубрика🔥🔥🔥:
⚖️ This vs That — «Это или то»
Сравнение похожих штук, между которыми все путаются
Мы стараемся для вас 💛
🔥 — если ждали новую рубрику
🐍Вопросы с собесов -> ProstoPython
⚖️ This vs That — «Это или то»
Сравнение похожих штук, между которыми все путаются
Мы стараемся для вас 💛
🔥 — если ждали новую рубрику
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🔥3
⚖️ This vs That:
Оба — методы без
staticmethod — функция, которая просто живёт внутри класса
Не получает ни
Если убрать
classmethod — метод, который знает свой класс
Первым аргументом получает
1. Альтернативные конструкторы
2. Корректная работа с наследованием
Если бы внутри было
Главное отличие в одной фразе
Если методу не нужен ни
Если нужно создать объект *того же класса, что вызвал метод* — это
🐍Вопросы с собесов -> ProstoPython
staticmethod vs classmethodОба — методы без
self. Оба вызываются через класс. Разница ловится за 30 секунд, если понять одну вещь.staticmethod — функция, которая просто живёт внутри класса
Не получает ни
self, ни cls. Не знает ни про экземпляр, ни про класс. По сути — обычная функция, которую сложили в namespace класса для удобства.
class Temperature:
@staticmethod
def c_to_f(celsius):
return celsius * 9/5 + 32
Temperature.c_to_f(100) # 212
Если убрать
staticmethod и вынести функцию наружу — ничего не сломается. Это и есть маркер.classmethod — метод, который знает свой класс
Первым аргументом получает
cls — сам класс. Это даёт две суперспособности:1. Альтернативные конструкторы
class User:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_dict(cls, data):
return cls(data["name"], data["age"])
user = User.from_dict({"name": "Anna", "age": 30})
cls(...) вместо User(...) — важная деталь. Об этом ниже.2. Корректная работа с наследованием
class Admin(User):
pass
admin = Admin.from_dict({"name": "Bob", "age": 40})
print(type(admin)) # <class 'Admin'> ✅
Если бы внутри было
return User(...) — Admin.from_dict(...) вернул бы User. Это классическая ошибка.Главное отличие в одной фразе
staticmethod — про группировку.classmethod — про полиморфизм по классу.Если методу не нужен ни
self, ни cls — это staticmethod.Если нужно создать объект *того же класса, что вызвал метод* — это
classmethod.🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
🧰 Code Cleanup
Плохой код
Работает. Но это четыре строки там, где могла быть одна.
Чистый вариант
Та же логика, тот же ранний выход (
Зеркальный кейс — «все ли валидны»:
🐍Вопросы с собесов -> ProstoPython
Плохой код
def has_admin(users):
found = False
for user in users:
if user.role == "admin":
found = True
break
return found
Работает. Но это четыре строки там, где могла быть одна.
Чистый вариант
def has_admin(users):
return any(user.role == "admin" for user in users)
Та же логика, тот же ранний выход (
any ленивый — остановится на первом True), но без флага и break.Зеркальный кейс — «все ли валидны»:
# было
all_valid = True
for item in items:
if not item.is_valid():
all_valid = False
break
# стало
all_valid = all(item.is_valid() for item in items)
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
🏆4
❌ Rookie Mistakes
Делаешь список функций — каждая должна возвращать своё число:
Ожидаешь:
Получаешь:
Почему так
Лямбда не «запоминает» значение
К моменту вызова
Это называется late binding — переменные в замыкании резолвятся в момент вызова, а не определения.
Как правильно
Способ 1 — захватить значение через дефолтный аргумент:
Дефолты вычисляются в момент определения функции —
Способ 2 —
Вывод
Замыкания захватывают переменные, а не значения. Если в цикле создаёшь функции — всегда фиксируй переменную явно (
🐍Вопросы с собесов -> ProstoPython
Делаешь список функций — каждая должна возвращать своё число:
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])
Ожидаешь:
[0, 1, 2]Получаешь:
[2, 2, 2]Почему так
Лямбда не «запоминает» значение
i в момент создания. Она запоминает саму переменную i. А переменная одна на всех.К моменту вызова
f() цикл уже завершился, и i равно последнему значению — 2. Все три лямбды смотрят в одну и ту же ячейку памяти.Это называется late binding — переменные в замыкании резолвятся в момент вызова, а не определения.
Как правильно
Способ 1 — захватить значение через дефолтный аргумент:
funcs = [lambda i=i: i for i in range(3)]
Дефолты вычисляются в момент определения функции —
i фиксируется.Способ 2 —
functools.partial:from functools import partial
funcs = [partial(lambda x: x, i) for i in range(3)]
Вывод
Замыкания захватывают переменные, а не значения. Если в цикле создаёшь функции — всегда фиксируй переменную явно (
x=x в аргументах или partial).🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
👍4
📈 From O(n) to O(1):
Задача
Дан массив. Приходят запросы вида «найди сумму элементов от индекса
Наивное решение — O(n) на запрос
Один запрос — O(n). Тысяча запросов на массиве в миллион — 10⁹ операций. Сервер плачет.
Идея: один раз посчитать, дальше отвечать за O(1)
Префиксная сумма
Тогда сумма на отрезке
Из суммы «всё до
Код
Препроцессинг — O(n), один раз.
Каждый запрос — O(1).
На тысяче запросов вместо 10⁹ операций получаем
🐍Вопросы с собесов -> ProstoPython
Задача
Дан массив. Приходят запросы вида «найди сумму элементов от индекса
l до r включительно». Запросов много — тысячи или миллионы.nums = [3, 1, 4, 1, 5, 9, 2, 6]
query(1, 4) → 1 + 4 + 1 + 5 = 11
query(2, 6) → 4 + 1 + 5 + 9 + 2 = 21
Наивное решение — O(n) на запрос
def query(nums, l, r):
return sum(nums[l:r+1])
Один запрос — O(n). Тысяча запросов на массиве в миллион — 10⁹ операций. Сервер плачет.
Идея: один раз посчитать, дальше отвечать за O(1)
Префиксная сумма
prefix[i] — это сумма всех элементов до индекса i.nums = [3, 1, 4, 1, 5, 9, 2, 6]
prefix = [0, 3, 4, 8, 9, 14, 23, 25, 31]
prefix[i] = сумма nums[0..i-1]. Длина — n + 1 (с нулём в начале для удобства).Тогда сумма на отрезке
[l, r] — это:prefix[r+1] - prefix[l]
Из суммы «всё до
r включительно» вычитаем «всё до l не включая». Остаётся ровно нужный отрезок.Код
def build_prefix(nums):
prefix = [0] * (len(nums) + 1)
for i, n in enumerate(nums):
prefix[i + 1] = prefix[i] + n
return prefix
def query(prefix, l, r):
return prefix[r + 1] - prefix[l]
Препроцессинг — O(n), один раз.
Каждый запрос — O(1).
На тысяче запросов вместо 10⁹ операций получаем
n + 1000 — фактически линейное время.🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
❤4
🧠 Interview Thinking
Задача
Дана строка из скобок
Как думает junior
Сразу видит «надо считать скобки» и пишет:
Работает на
Junior часто радуется, что счётчик сошёлся, и не замечает, что порядок закрытия имеет значение.
Как думает сильный кандидат
Сначала задаёт себе вопрос: «Что я вообще проверяю?»
Не баланс чисел. А то, что каждая закрывающая скобка совпадает с последней открытой того же типа.
Это «последняя открытая, первая закрытая» — классический LIFO. Значит — стек.
Логика:
- открывающую — кидаем в стек
- закрывающую — смотрим, что наверху стека: если не пара, или стек пуст → не сбалансировано
- в конце стек должен быть пуст (если остались незакрытые — тоже false)
Тонкие моменты, которые отличают сильного кандидата
Сильный сам проговаривает edge cases, не дожидаясь вопроса:
- пустая строка →
- только закрывающие
- только открывающие
- смешанные с другими символами? → уточняет у интервьюера: «А в строке могут быть буквы, или только скобки?»
Последнее — особенно ценно. Уточнение требований до кода — маркер инженерного мышления.
Что хочет интервьюер
Не код. Код — побочный продукт.
Интервьюер слушает, как ты приходишь к идее стека. Идеальный путь:
1. «Проверять баланс счётчиком — недостаточно, порядок важен»
2. «Мне нужно помнить, что было открыто последним»
3. «Структура „последний вошёл — первый вышел“ — это стек»
4. «В Python это просто
Если ты пройдёшь этот путь вслух за 30 секунд — половина задачи решена ещё до первой строки кода.
🐍Вопросы с собесов -> ProstoPython
Задача
Дана строка из скобок
(), [], {}. Вернуть True, если они правильно сбалансированы."()[]{}" → True
"([{}])" → True
"(]" → False
"([)]" → False ← коварный кейс
"(((" → FalseКак думает junior
Сразу видит «надо считать скобки» и пишет:
def is_balanced(s):
count = 0
for ch in s:
if ch in "([{":
count += 1
else:
count -= 1
return count == 0
Работает на
"()()", ломается на "([)]" — там тоже баланс по числу, но порядок неправильный. Пройдёт по count == 0 и вернёт True. Бага.Junior часто радуется, что счётчик сошёлся, и не замечает, что порядок закрытия имеет значение.
Как думает сильный кандидат
Сначала задаёт себе вопрос: «Что я вообще проверяю?»
Не баланс чисел. А то, что каждая закрывающая скобка совпадает с последней открытой того же типа.
Это «последняя открытая, первая закрытая» — классический LIFO. Значит — стек.
def is_balanced(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in s:
if ch in "([{":
stack.append(ch)
else:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
Логика:
- открывающую — кидаем в стек
- закрывающую — смотрим, что наверху стека: если не пара, или стек пуст → не сбалансировано
- в конце стек должен быть пуст (если остались незакрытые — тоже false)
Тонкие моменты, которые отличают сильного кандидата
Сильный сам проговаривает edge cases, не дожидаясь вопроса:
- пустая строка →
True (стек пуст в конце ✅)- только закрывающие
")))" → False (стек пуст)- только открывающие
"(((" → False (стек не пуст в конце)- смешанные с другими символами? → уточняет у интервьюера: «А в строке могут быть буквы, или только скобки?»
Последнее — особенно ценно. Уточнение требований до кода — маркер инженерного мышления.
Что хочет интервьюер
Не код. Код — побочный продукт.
Интервьюер слушает, как ты приходишь к идее стека. Идеальный путь:
1. «Проверять баланс счётчиком — недостаточно, порядок важен»
2. «Мне нужно помнить, что было открыто последним»
3. «Структура „последний вошёл — первый вышел“ — это стек»
4. «В Python это просто
list с append / pop»Если ты пройдёшь этот путь вслух за 30 секунд — половина задачи решена ещё до первой строки кода.
🐍Вопросы с собесов -> ProstoPython
Telegram
Prosto Python | вопросы с собесов
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
❤4