try/except: ловим ошибки красиво 🚨
Когда приложение встречает неожиданные данные или «ломается» внешний сервис, — незакрытые исключения превращают всё в Traceback. С парой правильных конструкций Python можно превратить «красный экран ужаса» в контролируемое сообщение или план B.
🔹 Что такое try/except?
try — это блок кода, где «может пойти не так».
except — ловушка, которая перехватывает указанное исключение и решает, что делать дальше (залогировать, вернуть дефолт, повторить попытку).
🔸 Базовый синтаксис
Если int() выбросит ValueError, то except поймает его и программа продолжит жить.
🔹 Несколько исключений — одна обработка
Скобки позволяют задать кортеж типов.
🔹 else и finally: дополнительные возможности
• else — место для логики, которая нужна только при успехе.
• finally — гарантированное «уборочное» действие (закрыть файл, соединение).
✅ Когда применять try/except
🔹Работа с файлами, сетью, БД: внешние ресурсы ненадёжны.
🔹Парсинг пользовательского ввода или JSON из API.
🔹Конвертация типов (str → int/float) и потенциально «хрупкие» операции.
🔹Интеграция сторонних библиотек, где вы не контролируете внутренний код.
Когда приложение встречает неожиданные данные или «ломается» внешний сервис, — незакрытые исключения превращают всё в Traceback. С парой правильных конструкций Python можно превратить «красный экран ужаса» в контролируемое сообщение или план B.
🔹 Что такое try/except?
try — это блок кода, где «может пойти не так».
except — ловушка, которая перехватывает указанное исключение и решает, что делать дальше (залогировать, вернуть дефолт, повторить попытку).
🔸 Базовый синтаксис
try:
result = int(input("Введите число: "))
# пользователь мог ввести «abc»
except ValueError as err:
print("Нужно было число! ❌", err)
Если int() выбросит ValueError, то except поймает его и программа продолжит жить.
🔹 Несколько исключений — одна обработка
try:
price = float(raw_price)
# при значении «12,34» — ошибка
discount = price / qty
# qty может быть 0
except (ValueError, ZeroDivisionError) as err:
print("Проверьте ввод ➡️", err)
Скобки позволяют задать кортеж типов.
🔹 else и finally: дополнительные возможности
try:
conn = db.connect()
data = conn.fetch("SELECT * FROM users")
except db.DatabaseError as e:
logger.error("База недоступна: %s", e)
else:
# выполнится ТОЛЬКО если исключения не было
process(data)
finally:
# выполнится ВСЕГДА
conn.close()
• else — место для логики, которая нужна только при успехе.
• finally — гарантированное «уборочное» действие (закрыть файл, соединение).
✅ Когда применять try/except
🔹Работа с файлами, сетью, БД: внешние ресурсы ненадёжны.
🔹Парсинг пользовательского ввода или JSON из API.
🔹Конвертация типов (str → int/float) и потенциально «хрупкие» операции.
🔹Интеграция сторонних библиотек, где вы не контролируете внутренний код.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤2👍2
sorted() vs .sort(): когда применять тот или иной вариант ↕️
Python предоставляет два способа упорядочить данные: встроенную функцию sorted() и метод списка .sort(). Ниже — краткое сравнение и рекомендации по использованию.
Основные различия
1️⃣ sorted(iterable)
• Не изменяет исходный объект
• Возвращает новый отсортированный объект
• Принимает любой итерируемый (списки, строки, кортежи, генераторы)
2️⃣ list.sort()
• Сортирует список in-place (данные изменяются)
• Возвращает None
• Работает только со списками и экономит память, поскольку не создаёт копию
Пример
Общие параметры
🔹 key= — функция, определяющая порядок сортировки (напр. sorted(words, key=len))
🔹 reverse=True — сортировка по убыванию
🔹 Обе операции стабильные: элементы с одинаковым key сохраняют первоначальный порядок
Критерии выбора
🔹Требуется сохранить исходные данные без изменений → sorted()
🔹Нужно упорядочить не-list (строку, tuple, генератор) → sorted()
🔹Работа ведётся с крупным списком, важна экономия памяти → .sort()
🔹Планируется многократная пересортировка одного и того же списка → .sort()
🔹Сортировка встроена в цепочку выражений или генераторов → sorted()
⚠️ Особенности
🔹Метод .sort() всегда возвращает None; использование его результата в присваивании вызовет ошибку.
🔹При применении sorted() к очень большим коллекциям объём используемой памяти увеличивается, поскольку создаётся копия.
🔹Обе реализации основаны на алгоритме Timsort со средней сложностью O(N log N).
📌 Вывод
sorted() обеспечивает неизменность исходных данных и работает с любыми итерируемыми объектами. .sort() выполняет сортировку быстрее и экономнее по памяти, но только для списков и за счёт изменения объекта на месте. Используйте тот вариант, который соответствует конкретным требованиям задачи.
Python предоставляет два способа упорядочить данные: встроенную функцию sorted() и метод списка .sort(). Ниже — краткое сравнение и рекомендации по использованию.
Основные различия
1️⃣ sorted(iterable)
• Не изменяет исходный объект
• Возвращает новый отсортированный объект
• Принимает любой итерируемый (списки, строки, кортежи, генераторы)
2️⃣ list.sort()
• Сортирует список in-place (данные изменяются)
• Возвращает None
• Работает только со списками и экономит память, поскольку не создаёт копию
Пример
nums = [3, 1, 4, 1, 5]
sorted_nums = sorted(nums)
# → [1, 1, 3, 4, 5]
print(nums)
# исходный остаётся: [3, 1, 4, 1, 5]
nums.sort()
# сортировка на месте
print(nums)
# → [1, 1, 3, 4, 5]
Общие параметры
🔹 key= — функция, определяющая порядок сортировки (напр. sorted(words, key=len))
🔹 reverse=True — сортировка по убыванию
🔹 Обе операции стабильные: элементы с одинаковым key сохраняют первоначальный порядок
Критерии выбора
🔹Требуется сохранить исходные данные без изменений → sorted()
🔹Нужно упорядочить не-list (строку, tuple, генератор) → sorted()
🔹Работа ведётся с крупным списком, важна экономия памяти → .sort()
🔹Планируется многократная пересортировка одного и того же списка → .sort()
🔹Сортировка встроена в цепочку выражений или генераторов → sorted()
⚠️ Особенности
🔹Метод .sort() всегда возвращает None; использование его результата в присваивании вызовет ошибку.
🔹При применении sorted() к очень большим коллекциям объём используемой памяти увеличивается, поскольку создаётся копия.
🔹Обе реализации основаны на алгоритме Timsort со средней сложностью O(N log N).
📌 Вывод
sorted() обеспечивает неизменность исходных данных и работает с любыми итерируемыми объектами. .sort() выполняет сортировку быстрее и экономнее по памяти, но только для списков и за счёт изменения объекта на месте. Используйте тот вариант, который соответствует конкретным требованиям задачи.
👍6❤3🔥3
@property: геттеры-сеттеры «по-питоновски»
@property превращает обычные методы в «прозрачные» атрибуты. Класс продолжает выглядеть как работа с полями, но внутри можно валидировать входные данные, кэшировать результаты или менять реализацию — без изменения внешнего интерфейса.
🔹 Что делает @property
1️⃣ Позволяет объявить геттер — метод, который вызывается при чтении атрибута.
2️⃣ Через @<имя>.setter добавляется сеттер для записи.
3️⃣ При необходимости можно добавить @<имя>.deleter для удаления атрибута.
🔸 Мини-пример
Клиенту класса всё равно, что внутри есть логика: доступ идёт как к «обычному» полю.
Преимущества
🔹Инкапсуляция без шума. Проверки и вычисления скрыты, интерфейс лаконичный.
🔹Совместимость. Можно заменить публичное поле на property, не меняя вызовов в коде.
🔹Ленивая инициализация и кэш. Первый вызов рассчитывает значение, а setter/делитер управляют кэшем.
⚠️ Нюансы
🔹Логика в property должна оставаться быстрой; тяжёлые операции лучше вызывать явно.
🔹Сеттер обязателен, если атрибут нужно менять; без него объект станет «только для чтения».
✅ Когда использовать
🔹Необходимо валидировать входные данные при присвоении.
🔹Значение должно вычисляться на лету (площадь, кэшированное представление).
🔹Планируется изменить внутреннее хранилище данных, сохранив старый API.
@property превращает обычные методы в «прозрачные» атрибуты. Класс продолжает выглядеть как работа с полями, но внутри можно валидировать входные данные, кэшировать результаты или менять реализацию — без изменения внешнего интерфейса.
🔹 Что делает @property
1️⃣ Позволяет объявить геттер — метод, который вызывается при чтении атрибута.
2️⃣ Через @<имя>.setter добавляется сеттер для записи.
3️⃣ При необходимости можно добавить @<имя>.deleter для удаления атрибута.
🔸 Мини-пример
class Rectangle:
def __init__(self, w, h):
# вызовет setter
self.width = w
self.height = h
# ---- width ----
@property
def width(self):
return self._w
@width.setter
def width(self, v):
if v <= 0:
raise ValueError('> 0')
self._w = v
# ---- area (read-only) ----
@property
def area(self):
return self.width * self.height
Клиенту класса всё равно, что внутри есть логика: доступ идёт как к «обычному» полю.
Преимущества
🔹Инкапсуляция без шума. Проверки и вычисления скрыты, интерфейс лаконичный.
🔹Совместимость. Можно заменить публичное поле на property, не меняя вызовов в коде.
🔹Ленивая инициализация и кэш. Первый вызов рассчитывает значение, а setter/делитер управляют кэшем.
⚠️ Нюансы
🔹Логика в property должна оставаться быстрой; тяжёлые операции лучше вызывать явно.
🔹Сеттер обязателен, если атрибут нужно менять; без него объект станет «только для чтения».
✅ Когда использовать
🔹Необходимо валидировать входные данные при присвоении.
🔹Значение должно вычисляться на лету (площадь, кэшированное представление).
🔹Планируется изменить внутреннее хранилище данных, сохранив старый API.
👍4🔥2❤1
5 вопросов, которые почти наверняка зададут на Python-собеседовании 🧩
Ниже — короткая шпаргалка в стиле «вопрос → суть ответа → мини-пример». Сохраните пост, чтобы повторить перед интервью.
🔹 list vs tuple
Что спросят: «чем отличаются и зачем нужен кортеж?»
list изменяем, поэтому занимает больше памяти и не может быть ключом словаря. tuple неизменяем, легче и хэшируем — hash((1,2,3)) работает.
🔹 *args и **kwargs
Что спросят: «Как работает распаковка и порядок параметров?»
*args собирает все дополнительные позиционные аргументы в кортеж, а **kwargs — именованные в словарь.
В сигнатуре сначала идут обычные параметры, затем *args, потом именованные с значениями по умолчанию и в конце **kwargs.
🔹 yield vs return
Что спросят: «Чем генератор лучше обычной функции?»
yield приостанавливает функцию, сохраняя её состояние, поэтому следующая итерация продолжается с того же места.
Генератор выдаёт элементы по запросу, экономя память и позволяя обрабатывать большие потоки данных.
🔹 Почему += со строками медленный?
Что спросят: «Где здесь проблема неизменяемости?»
str неизменяем, поэтому при каждом += создаётся новая копия и суммарная сложность растёт до O(n²).
Накопите части в списке и соедините их одним ''.join() — это линейно по времени и памяти.
🔹 GIL и многопоточность
Что спросят: «Почему потоки не ускоряют CPU-bound код в CPython?»
GIL (Global Interpreter Lock) позволяет выполнять байт-код
только одному потоку CPython в любой момент времени.
Поэтому CPU-bound задачи не параллелятся потоками, а для параллели
используют multiprocessing, C-расширения или I/O-ориентированный asyncio.
Ниже — короткая шпаргалка в стиле «вопрос → суть ответа → мини-пример». Сохраните пост, чтобы повторить перед интервью.
🔹 list vs tuple
Что спросят: «чем отличаются и зачем нужен кортеж?»
# list — изменяем
a = [1, 2]; a.append(3)
# tuple — неизменяем
b = (1, 2, 3)
# ✅ может быть ключом dict
hash(b)
list изменяем, поэтому занимает больше памяти и не может быть ключом словаря. tuple неизменяем, легче и хэшируем — hash((1,2,3)) работает.
🔹 *args и **kwargs
Что спросят: «Как работает распаковка и порядок параметров?»
def demo(a, *args, z=0, **kw):
print(a, args, z, kw)
demo(1, 2, 3, z=4, x=5)
# → 1 | (2, 3) | 4 | {'x': 5}
*args собирает все дополнительные позиционные аргументы в кортеж, а **kwargs — именованные в словарь.
В сигнатуре сначала идут обычные параметры, затем *args, потом именованные с значениями по умолчанию и в конце **kwargs.
🔹 yield vs return
Что спросят: «Чем генератор лучше обычной функции?»
def squares(n):
for i in range(n):
yield i * i
yield приостанавливает функцию, сохраняя её состояние, поэтому следующая итерация продолжается с того же места.
Генератор выдаёт элементы по запросу, экономя память и позволяя обрабатывать большие потоки данных.
🔹 Почему += со строками медленный?
Что спросят: «Где здесь проблема неизменяемости?»
# неэффективно
s = ''
for w in words:
# каждая конкатенация создаёт новую строку
s += w
# эффективно
s = ''.join(words)
str неизменяем, поэтому при каждом += создаётся новая копия и суммарная сложность растёт до O(n²).
Накопите части в списке и соедините их одним ''.join() — это линейно по времени и памяти.
🔹 GIL и многопоточность
Что спросят: «Почему потоки не ускоряют CPU-bound код в CPython?»
GIL (Global Interpreter Lock) позволяет выполнять байт-код
только одному потоку CPython в любой момент времени.
Поэтому CPU-bound задачи не параллелятся потоками, а для параллели
используют multiprocessing, C-расширения или I/O-ориентированный asyncio.
👍4🔥3❤1
os.path.join и Pathlib: кросс-платформенные пути 🛣️
Когда скрипт должен работать и в Windows, и в Linux, ручная склейка "/" или "\\" быстро приводит к багам. Используйте встроенные инструменты, которые сами подставят нужный разделитель.
Почему это важно❗️
Пути к файлам отличаются:
🔹Windows → C:\data\file.txt
🔹Linux/Mac → /home/user/file.txt
os.path.join() и pathlib.Path автоматически подставляют правильный разделитель и избегают двойных «//» или «\».
🔸 os.path.join — «старый надёжный»
Берёт любое количество частей и склеивает безопасно.
🔹 Pathlib — «современный» и удобный
⚠️ Подводные камни
🔹 Не склеивайте пути через + или f-строки — это ломается на другой ОС.
🔹 В os.path.join если одна часть начинается с ведущего «/» или диска (C:\), все предыдущие игнорируются.
🔹 В Path оператор / работает только между объектами Path и/или строками, но не с числами — приведите к str.
✅ Когда применять
🔹 Пишете скрипт, который будут запускать коллеги на разных ОС.
🔹 Строите сложные вложённые пути: base / 'raw' / date / 'file.parquet'.
Когда скрипт должен работать и в Windows, и в Linux, ручная склейка "/" или "\\" быстро приводит к багам. Используйте встроенные инструменты, которые сами подставят нужный разделитель.
Почему это важно
Пути к файлам отличаются:
🔹Windows → C:\data\file.txt
🔹Linux/Mac → /home/user/file.txt
os.path.join() и pathlib.Path автоматически подставляют правильный разделитель и избегают двойных «//» или «\».
🔸 os.path.join — «старый надёжный»
import os
folder = 'data'
name = 'report.csv'
path = os.path.join('C:\\tmp', folder, name)
print(path)
# Windows: C:\tmp\data\report.csv
Берёт любое количество частей и склеивает безопасно.
🔹 Pathlib — «современный» и удобный
from pathlib import Path
# /home/<user> или C:\Users\<user>
base = Path.home()
path = base / 'data' / 'report.csv'
print(path)
⚠️ Подводные камни
🔹 Не склеивайте пути через + или f-строки — это ломается на другой ОС.
🔹 В os.path.join если одна часть начинается с ведущего «/» или диска (C:\), все предыдущие игнорируются.
🔹 В Path оператор / работает только между объектами Path и/или строками, но не с числами — приведите к str.
✅ Когда применять
🔹 Пишете скрипт, который будут запускать коллеги на разных ОС.
🔹 Строите сложные вложённые пути: base / 'raw' / date / 'file.parquet'.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3🔥2
Опубликовали разбор 2 задач из собеседования на аналитика данных в Яндекс 🔥
Статья:
https://vc.ru/hr/2069090-analiticheskie-zadachi-yandeksa
Статья:
https://vc.ru/hr/2069090-analiticheskie-zadachi-yandeksa
Please open Telegram to view this post
VIEW IN TELEGRAM
vc.ru
Две аналитические задачи с интервью «Яндекса»: разбор и практика на Python Academy — Карьера на vc.ru
Николай Ладанов Карьера 21м
🔥3❤2👍2