🛑 Твой код завис навсегда? Исправляем!
Знаете ли вы, что по умолчанию библиотека
Если сервер, к которому вы обращаетесь, "упал" или просто завис, ваш Python-скрипт тоже встанет и будет висеть вечно, пока вы не убьете процесс вручную. В продакшене (да и в пет-проектах) это недопустимо! 🚫
✅ Решение: Всегда используйте
Параметр
Пример безопасного кода:
💡 Совет: Хорошей практикой считается ставить таймаут в диапазоне 3–10 секунд для обычных запросов.
Проверьте свои старые проекты, есть ли там
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Знаете ли вы, что по умолчанию библиотека
requests ждет ответа от сервера бесконечно?Если сервер, к которому вы обращаетесь, "упал" или просто завис, ваш Python-скрипт тоже встанет и будет висеть вечно, пока вы не убьете процесс вручную. В продакшене (да и в пет-проектах) это недопустимо! 🚫
✅ Решение: Всегда используйте
timeoutПараметр
timeout указывает, сколько секунд ждать ответа, прежде чем выбросить ошибку и продолжить работу.Пример безопасного кода:
import requests
from requests.exceptions import Timeout, ConnectionError
url = "https://httpbin.org/delay/5" # Сервер ответит через 5 сек
try:
# Ставим таймаут 2 секунды.
# Если сервер не ответит за 2 сек — скрипт не зависнет!
response = requests.get(url, timeout=2)
response.raise_for_status() # Проверка на ошибки 4xx/5xx
print("Успех:", response.json())
except Timeout:
print("⏰ Ошибка: Сервер отвечает слишком долго!")
except ConnectionError:
print("🔌 Ошибка: Нет интернета или сайт недоступен.")
except Exception as e:
print(f"Что-то пошло не так: {e}")
💡 Совет: Хорошей практикой считается ставить таймаут в диапазоне 3–10 секунд для обычных запросов.
Проверьте свои старые проекты, есть ли там
timeout? Если нет, самое время добавить! 👨💻📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍6
🚀 Синхронность vs Асинхронность: Ускоряем код в 10 раз
Представьте, что вы стоите в очереди в Макдональдс.
🐢 Синхронный подход (как
Кассир принимает ваш заказ, уходит на кухню, ждет, пока пожарится картошка, наливает колу, отдает заказ вам и только потом обращается к следующему человеку в очереди. Медленно? Ужасно медленно!
⚡️ Асинхронный подход (как
Кассир принимает заказ, кричит на кухню "Свободная касса!" и сразу берет заказ у следующего, пока ваш готовится. Работа идет параллельно.
В Python для этого используется библиотека
Сравним на практике:
Допустим, нам нужно скачать 10 страниц.
Результат:
Если
🛠 Установка:
⚠️ Важно: Не используйте это для атак на сайты (DDoS). Сервер может забанить вас за слишком большое количество запросов в секунду.
Сохраняй, пригодится для парсинга больших объемов данных! 🔥
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Представьте, что вы стоите в очереди в Макдональдс.
🐢 Синхронный подход (как
requests):Кассир принимает ваш заказ, уходит на кухню, ждет, пока пожарится картошка, наливает колу, отдает заказ вам и только потом обращается к следующему человеку в очереди. Медленно? Ужасно медленно!
⚡️ Асинхронный подход (как
aiohttp):Кассир принимает заказ, кричит на кухню "Свободная касса!" и сразу берет заказ у следующего, пока ваш готовится. Работа идет параллельно.
В Python для этого используется библиотека
aiohttp и ключевые слова async / await.Сравним на практике:
Допустим, нам нужно скачать 10 страниц.
import asyncio
import aiohttp
import time
# Функция для одного запроса
async def fetch_page(session, url):
async with session.get(url) as response:
return response.status
async def main():
urls = ["https://google.com" for _ in range(10)] # 10 запросов
async with aiohttp.ClientSession() as session:
tasks = []
for url in urls:
# Создаем задачи, но еще не запускаем их ожидание
tasks.append(fetch_page(session, url))
# Запускаем все задачи одновременно!
await asyncio.gather(*tasks)
start = time.time()
# Запуск асинхронного цикла
asyncio.run(main())
print(f"Время выполнения: {time.time() - start:.2f} сек")
Результат:
Если
requests будет делать это ~10 секунд (по 1 сек на запрос), то aiohttp справится за ~1.2 секунды. Он просто отправит все 10 запросов разом и будет ждать ответы.🛠 Установка:
pip install aiohttp⚠️ Важно: Не используйте это для атак на сайты (DDoS). Сервер может забанить вас за слишком большое количество запросов в секунду.
Сохраняй, пригодится для парсинга больших объемов данных! 🔥
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3😱1🥴1
🤖 Твой первый Telegram-бот на aiogram
Мы уже выяснили, что асинхронность это круто. А где она используется чаще всего? Конечно, в Telegram-ботах!
Сегодня напишем "Эхо-бота" - это как "Hello World" в мире ботов. Он будет просто повторять всё, что мы ему напишем.
🛠 Подготовка:
1. Идем к «отцу всех ботов» - @BotFather.
2. Пишем
3. Получаем API TOKEN (длинная строка символов).
4. Устанавливаем библиотеку:
💻 Код (всего 20 строк):
🧩 Разбор магии:
🟢
🟢
🟢
Скопируй, вставь токен и запусти. Поздравляю, ты только что создал своего бота! 🎉
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Мы уже выяснили, что асинхронность это круто. А где она используется чаще всего? Конечно, в Telegram-ботах!
Сегодня напишем "Эхо-бота" - это как "Hello World" в мире ботов. Он будет просто повторять всё, что мы ему напишем.
🛠 Подготовка:
1. Идем к «отцу всех ботов» - @BotFather.
2. Пишем
/newbot, даем имя и юзернейм.3. Получаем API TOKEN (длинная строка символов).
4. Устанавливаем библиотеку:
pip install aiogram💻 Код (всего 20 строк):
import asyncio
import logging
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
# Вставь сюда токен от BotFather
TOKEN = "ВАШ_ТОКЕН_ЗДЕСЬ"
# Включаем логирование, чтобы видеть ошибки в консоли
logging.basicConfig(level=logging.INFO)
# Создаем объекты бота и диспетчера
bot = Bot(token=TOKEN)
dp = Dispatcher()
# 1. Обработчик команды /start
@dp.message(CommandStart())
async def cmd_start(message: types.Message):
await message.answer("Привет! Я твой первый бот на aiogram 🚀")
# 2. Обработчик любого текста (Эхо)
@dp.message()
async def echo_handler(message: types.Message):
# Метод .answer() отправляет ответ в тот же чат
await message.answer(f"Ты написал: {message.text}")
# Запуск процесса опроса (polling)
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
🧩 Разбор магии:
Dispatcher (dp) - это мозг бота. Он получает сообщения от Telegram и решает, какой функции их передать.@dp.message(...) - это декораторы. Они "фильтруют" сообщения.await message.answer(...) - асинхронная отправка сообщения. Пока бот отправляет ответ тебе, он может параллельно обрабатывать сообщения от других пользователей!Скопируй, вставь токен и запусти. Поздравляю, ты только что создал своего бота! 🎉
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3🤔1
🎛 Делаем бота удобным: Кнопки и Меню
Никто не любит вводить команды вручную (
1. Reply-кнопки: Находятся под полем ввода. Идеальны для главного меню.
2. Inline-кнопки: Прикреплены к конкретному сообщению. Идеальны для ссылок, лайков или навигации.
Давайте добавим оба вида в нашего бота!
🛠 Код:
💡 В чем сила Builders?
Метод
Сохраняй, чтобы не гуглить синтаксис каждый раз! 💾
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Никто не любит вводить команды вручную (
/settings, /help). Пользователи любят тыкать пальцем! В Telegram есть два вида кнопок:1. Reply-кнопки: Находятся под полем ввода. Идеальны для главного меню.
2. Inline-кнопки: Прикреплены к конкретному сообщению. Идеальны для ссылок, лайков или навигации.
Давайте добавим оба вида в нашего бота!
🛠 Код:
from aiogram.types import KeyboardButton, InlineKeyboardButton
from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder
# --- 1. Создаем Reply-клавиатуру (Главное меню) ---
def get_main_menu():
# Инициализируем билдер
builder = ReplyKeyboardBuilder()
# Добавляем кнопки
builder.add(KeyboardButton(text="🔥 Профиль"))
builder.add(KeyboardButton(text="⚙️ Настройки"))
builder.add(KeyboardButton(text="📈 Статистика"))
# Настраиваем сетку: 2 кнопки в первом ряду, 1 во втором
builder.adjust(2, 1)
# resize_keyboard=True делает кнопки компактными
return builder.as_markup(resize_keyboard=True)
# --- 2. Создаем Inline-клавиатуру (Ссылка) ---
def get_url_keyboard():
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(
text="↗️ Подписаться на канал",
url="https://t.me/pythonofff"
))
return builder.as_markup()
# --- Используем в хэндлере ---
@dp.message(Command("start"))
async def cmd_start(message: types.Message):
await message.answer(
"Привет! Вот твое меню 👇",
reply_markup=get_main_menu()
)
await message.answer(
"А это инлайн-кнопка со ссылкой:",
reply_markup=get_url_keyboard()
)
💡 В чем сила Builders?
Метод
.adjust(2, 1) позволяет одной строчкой настроить "сетку" кнопок. Раньше для этого приходилось писать сложные циклы списков!Сохраняй, чтобы не гуглить синтаксис каждый раз! 💾
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3
✨ Магия Python: Как работают декораторы?
Вы постоянно видите их в коде:
В Python функции - это объекты. Их можно передавать в другие функции, как обычные переменные.
Декоратор - это просто функция, которая принимает другую функцию, "обертывает" её в дополнительный код и возвращает обратно.
Представьте, что у вас есть подарок (функция). Декоратор - это упаковочная бумага. Подарок внутри тот же, но теперь он выглядит и ведет себя немного иначе.
Пример: Декоратор-логгер
Допустим, мы хотим автоматически писать в консоль, когда функция запустилась и когда завершилась.
Результат в консоли:
🤯 Что происходит под капотом?
Синтаксис с
А как это работает в ботах (@dp.message)?
В библиотеках типа
Когда вы пишете
Итог: Декораторы нужны, чтобы добавить логику вокруг функции (проверка прав доступа, замер скорости, логирование), не меняя её код внутри.
Ставь ❤️, если магия рассеялась и стало понятнее!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Вы постоянно видите их в коде:
@bot.message_handler, @app.route, @staticmethod. Но что на самом деле делает этот символ @?В Python функции - это объекты. Их можно передавать в другие функции, как обычные переменные.
Декоратор - это просто функция, которая принимает другую функцию, "обертывает" её в дополнительный код и возвращает обратно.
Представьте, что у вас есть подарок (функция). Декоратор - это упаковочная бумага. Подарок внутри тот же, но теперь он выглядит и ведет себя немного иначе.
Пример: Декоратор-логгер
Допустим, мы хотим автоматически писать в консоль, когда функция запустилась и когда завершилась.
def my_logger(func):
def wrapper():
print("📢 Запускаю функцию...")
func() # Вызываем оригинальную функцию
print("✅ Функция отработала!")
return wrapper
# Применяем декоратор
@my_logger
def say_hello():
print("Привет, мир!")
# Вызываем
say_hello()
Результат в консоли:
📢 Запускаю функцию...
Привет, мир!
✅ Функция отработала!
🤯 Что происходит под капотом?
Синтаксис с
@ - это просто "сахар" (упрощение). На самом деле Python делает вот это:
# Это:
@my_logger
def say_hello(): ...
# Равносильно этому:
def say_hello(): ...
say_hello = my_logger(say_hello)
А как это работает в ботах (@dp.message)?
В библиотеках типа
aiogram декораторы часто используются для регистрации.Когда вы пишете
@dp.message(), декоратор не меняет код вашей функции, а сообщает Диспетчеру: "Эй, запомни эту функцию! Если придет сообщение, нужно запустить именно её".Итог: Декораторы нужны, чтобы добавить логику вокруг функции (проверка прав доступа, замер скорости, логирование), не меняя её код внутри.
Ставь ❤️, если магия рассеялась и стало понятнее!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
❤7👍2
⚡ Lambda: Функции-однострочники
В Python часто бывают ситуации, когда вам нужна маленькая функция всего один раз. Например, чтобы отсортировать список по хитрому правилу.
Писать для этого полноценный
Синтаксис прост:
Сравните:
🔥 Где это реально нужно?
Чаще всего - внутри функций
Пример из жизни:
У нас есть список студентов и их баллов. Нам нужно отсортировать их не по имени, а по баллам.
Внутри
🛑 Когда НЕ надо использовать Lambda:
Не присваивайте лямбды переменным, если планируете использовать их много раз.
Лямбды созданы, чтобы быть "одноразовыми"!
Используете лямбды или предпочитаете старый добрый
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
В Python часто бывают ситуации, когда вам нужна маленькая функция всего один раз. Например, чтобы отсортировать список по хитрому правилу.
Писать для этого полноценный
def, придумывать имя и занимать 3 строки кода - лень и некрасиво. Тут на сцену выходят Lambda-функции (они же анонимные функции).Синтаксис прост:
lambda аргументы: выражениеСравните:
# Классический способ
def square(x):
return x ** 2
# Lambda-стиль
sq = lambda x: x ** 2
🔥 Где это реально нужно?
Чаще всего - внутри функций
sorted(), min(), max(), map() или filter().Пример из жизни:
У нас есть список студентов и их баллов. Нам нужно отсортировать их не по имени, а по баллам.
students = [
("Антон", 50),
("Вика", 90),
("Борис", 75)
]
# Сортируем по 2-му элементу кортежа (x[1])
sorted_students = sorted(students, key=lambda x: x[1])
print(sorted_students)
# [('Антон', 50), ('Борис', 75), ('Вика', 90)]
Внутри
key= мы на лету создали функцию, которая принимает студента x и возвращает его балл x[1]. sorted использует это значение для сортировки.🛑 Когда НЕ надо использовать Lambda:
Не присваивайте лямбды переменным, если планируете использовать их много раз.
# ❌ Плохо (нарушает PEP 8):
f = lambda x: x * 2
# ✅ Хорошо:
def f(x):
return x * 2
Лямбды созданы, чтобы быть "одноразовыми"!
Используете лямбды или предпочитаете старый добрый
def? 👇📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3❤1
⚡ Магия одной строки: List Comprehension
Вы всё еще пишете циклы для заполнения списков вот так?
Это работает, но это "старая школа". В Python есть способ сделать это элегантнее, быстрее и понятнее - Списковые включения.
Как это выглядит:
Тот же самый код выше превращается в:
🚀 Почему это круто?
1. Лаконичность: Меньше кода меньше багов.
2. Скорость: Это работает быстрее обычного цикла
Уровень PRO: Добавляем условия
Внутри можно использовать
Задача: Оставить только четные числа и умножить их на 10.
💡 Совет: Не увлекайтесь! Если ваше выражение не влезает в одну строку или становится слишком сложным (например, вложенные циклы), лучше вернитесь к старому доброму
Часто используете эту конструкцию? Ставьте 🔥!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Вы всё еще пишете циклы для заполнения списков вот так?
squares = []
for x in range(10):
squares.append(x ** 2)
Это работает, но это "старая школа". В Python есть способ сделать это элегантнее, быстрее и понятнее - Списковые включения.
Как это выглядит:
[выражение for элемент in список]Тот же самый код выше превращается в:
squares = [x ** 2 for x in range(10)]
🚀 Почему это круто?
1. Лаконичность: Меньше кода меньше багов.
2. Скорость: Это работает быстрее обычного цикла
for, потому что метод .append() не вызывается на каждой итерации (оптимизация на уровне C).Уровень PRO: Добавляем условия
Внутри можно использовать
if, чтобы фильтровать данные на лету.Задача: Оставить только четные числа и умножить их на 10.
numbers = [1, 2, 3, 4, 5, 6]
# Читается как английское предложение:
# "x умножить на 10 для каждого x в numbers, если x четный"
result = [x * 10 for x in numbers if x % 2 == 0]
print(result)
# [20, 40, 60]
💡 Совет: Не увлекайтесь! Если ваше выражение не влезает в одну строку или становится слишком сложным (например, вложенные циклы), лучше вернитесь к старому доброму
for. Читаемость важнее понтов!Часто используете эту конструкцию? Ставьте 🔥!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍6🔥3
💾 Бесконечность не предел: Магия генераторов (yield)
В прошлом посте мы восхищались списковыми включениями
Представьте, что вам нужно обработать файл весом 10 ГБ. Если вы попытаетесь загрузить его в список
Тут на помощь приходят Генераторы.
В чем отличие?
🟢 📦 Список (
🟢 ⚙️ Генератор: Не хранит данные. Он генерирует следующее значение только тогда, когда вы его попросите. Как рассказчик, который придумывает историю на ходу.
Как создать?
1. Генераторное выражение: Просто замените квадратные скобки
Разница колоссальная! Генератор весит копейки, даже если в нем миллиард чисел.
2. Функция с
Если логика сложная, используем функцию. Вместо
🚀 Итог: Если вам не нужен доступ ко всем элементам сразу (например, по индексу
Знали про
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
В прошлом посте мы восхищались списковыми включениями
[...]. Но у них есть фатальный недостаток: они создают весь список в памяти сразу.Представьте, что вам нужно обработать файл весом 10 ГБ. Если вы попытаетесь загрузить его в список
read_lines(), ваш компьютер скажет "Memory Error" и программа упадет. 💥Тут на помощь приходят Генераторы.
В чем отличие?
list): Хранит все элементы в памяти. Как готовая книга - все страницы уже напечатаны.Как создать?
1. Генераторное выражение: Просто замените квадратные скобки
[] на круглые ().
import sys
# Список (создает миллион чисел в памяти)
my_list = [x for x in range(1_000_000)]
print(f"List size: {sys.getsizeof(my_list)} bytes")
# ~8 000 000 байт (8 МБ)
# Генератор (просто формула)
my_gen = (x for x in range(1_000_000))
print(f"Gen size: {sys.getsizeof(my_gen)} bytes")
# ~100 байт (!!!)
Разница колоссальная! Генератор весит копейки, даже если в нем миллиард чисел.
2. Функция с
yield:Если логика сложная, используем функцию. Вместо
return (который убивает функцию и возвращает результат), пишем yield (который ставит на паузу и отдает значение).
def endless_numbers():
n = 0
while True: # Бесконечный цикл!
yield n
n += 1
# Можно брать по одному
gen = endless_numbers()
print(next(gen)) # 0
print(next(gen)) # 1
# Программа не зависнет, несмотря на while True
🚀 Итог: Если вам не нужен доступ ко всем элементам сразу (например, по индексу
list[10]), а вы просто перебираете их в цикле for - всегда используйте генераторы.Знали про
sys.getsizeof? Проверьте свои списки! 😉📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🔄 Хватит писать
Новички часто переносят привычки из других языков в Python. Самый частый пример это циклы.
❌ Как пишет новичок:
Если нужно получить элемент списка И его индекс:
Это работает, но выглядит громоздко и не "по-питоньи".
✅ 1. Используем
Эта функция сразу выдает и счетчик, и само значение. Код становится чище!
💡 Фишка: Аргумент
❌ Как пишет новичок:
Если нужно пройтись сразу по двум спискам (имена и зарплаты):
✅ 2. Используем
Функция
⚠️ Важно: Если списки разной длины,
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
range(len(...))!Новички часто переносят привычки из других языков в Python. Самый частый пример это циклы.
❌ Как пишет новичок:
Если нужно получить элемент списка И его индекс:
names = ["Анна", "Борис", "Олег"]
# Стиль C/Java
for i in range(len(names)):
print(f"{i}: {names[i]}")
Это работает, но выглядит громоздко и не "по-питоньи".
✅ 1. Используем
enumerateЭта функция сразу выдает и счетчик, и само значение. Код становится чище!
for i, name in enumerate(names, start=1):
print(f"{i}: {name}")
💡 Фишка: Аргумент
start=1 позволяет начать нумерацию не с нуля, а с единицы (полезно для вывода списков пользователю).❌ Как пишет новичок:
Если нужно пройтись сразу по двум спискам (имена и зарплаты):
salaries = [100, 200, 300]
for i in range(len(names)):
print(f"{names[i]} получает {salaries[i]}")
✅ 2. Используем
zipФункция
zip (молния 🤐) "сшивает" несколько списков в один, как застежка.
for name, salary in zip(names, salaries):
print(f"{name} получает {salary}")
⚠️ Важно: Если списки разной длины,
zip остановится, когда закончится самый короткий из них. Остальные "хвосты" будут отброшены (если не использовать zip_longest из itertools).📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍11
Изменение в контекстных менеджерах
Как вы знаете, для удобного управления жизненным циклом ресурсов в python существуют контекстные менеджеры. Но до недавнего времени, чтобы открыть несколько ресурсов в рамках одной области видимости with нам требовалось либо прописывать их в одну строку либо использовать синтаксис переноса - обратный слеш \ (но это противоречит PEP8).
С выходом python 3.10 появился новый синтаксис, позволяющий в круглых скобках указывать несколько контекстных менеджеров. А также мы можем использовать переменную созданную одним контекстным менеджером в рамках следующего за ним менеджера.
Это стало возможным благодаря появлению нового синтаксического анализатора PEG в python 3.9. И, строго говоря, python 3.9 уже допускал данный синтаксис, хотя официально еще не поддерживался.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Как вы знаете, для удобного управления жизненным циклом ресурсов в python существуют контекстные менеджеры. Но до недавнего времени, чтобы открыть несколько ресурсов в рамках одной области видимости with нам требовалось либо прописывать их в одну строку либо использовать синтаксис переноса - обратный слеш \ (но это противоречит PEP8).
С выходом python 3.10 появился новый синтаксис, позволяющий в круглых скобках указывать несколько контекстных менеджеров. А также мы можем использовать переменную созданную одним контекстным менеджером в рамках следующего за ним менеджера.
Это стало возможным благодаря появлению нового синтаксического анализатора PEG в python 3.9. И, строго говоря, python 3.9 уже допускал данный синтаксис, хотя официально еще не поддерживался.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3
🔮 Магия Множеств:
Представьте задачу: у вас есть два списка подписчиков - из Instagram и из Telegram.
1. Нужно найти тех, кто подписан и там, и там.
2. Нужно найти тех, кто есть в Telegram, но нет в Instagram.
❌ Способ новичка (Циклы):
Долго, скучно, медленно (O(n*m)).
✅ Способ Профи (Множества):
Множества в Python работают как круги Эйлера в математике.
💡 И самый главный трюк:
Как быстро убрать дубликаты из списка? Просто превратите его в множество!
🚀 Скорость: Поиск в множестве (
Используйте силу математики, чтобы писать меньше кода! 🧠
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
set круче списковПредставьте задачу: у вас есть два списка подписчиков - из Instagram и из Telegram.
1. Нужно найти тех, кто подписан и там, и там.
2. Нужно найти тех, кто есть в Telegram, но нет в Instagram.
❌ Способ новичка (Циклы):
insta = ["max", "leo", "kate"]
tg = ["leo", "alex", "kate"]
common = []
for user in insta:
if user in tg:
common.append(user)
Долго, скучно, медленно (O(n*m)).
✅ Способ Профи (Множества):
Множества в Python работают как круги Эйлера в математике.
# Создаем множества
insta = {"max", "leo", "kate"}
tg = {"leo", "alex", "kate"}
# 1. Пересечение (&) - кто есть ВЕЗДЕ
print(insta & tg)
# Вывод: {'leo', 'kate'}
# 2. Разность (-) - кто есть в TG, но НЕТ в Insta
print(tg - insta)
# Вывод: {'alex'}
# 3. Симметричная разность (^) - уникальные для каждой платформы
print(insta ^ tg)
# Вывод: {'max', 'alex'}
💡 И самый главный трюк:
Как быстро убрать дубликаты из списка? Просто превратите его в множество!
ids = [1, 2, 2, 3, 3, 3]
unique_ids = list(set(ids))
print(unique_ids) # [1, 2, 3]
🚀 Скорость: Поиск в множестве (
val in my_set) происходит почти мгновенно (), в отличие от списка, который нужно перебирать целиком.Используйте силу математики, чтобы писать меньше кода! 🧠
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍7👏2
Логирование
Логировние является неотъемлемой частью разработки. Логи показывают информацию о текущем состоянии программы. И чем лучше выстроено логирование, тем проще будет разобраться в нестандартных ситуациях.
Python поставляется для этих целей с гибким модулем logging. Для создания объекта Logger, вызываем функцию getLogger, передавая в нее имя логера.
Созданный объект Logger предоставляет методы для записи сообщений разного уровня (DEBUG, INFO, WARNING, ERROR, CRITICAL), что удобно для поиска нужной информации с применением фильтров.
По умолчанию в logging задан уровень WARNING, это означает, что сообщения уровня DEBUG и INFO будут игнорироваться при записи в лог. Изменить данное поведение можно с помощью метода setLevel, передав минимальный уровень, который будет отлавливаться.
Для отправки логов в сконфигурированные места используются обработчики. Мы можем использовать уже существующие хэндлеры, либо создать свой класс обработчика, унаследовавшись от базового класса Handler.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Логировние является неотъемлемой частью разработки. Логи показывают информацию о текущем состоянии программы. И чем лучше выстроено логирование, тем проще будет разобраться в нестандартных ситуациях.
Python поставляется для этих целей с гибким модулем logging. Для создания объекта Logger, вызываем функцию getLogger, передавая в нее имя логера.
Созданный объект Logger предоставляет методы для записи сообщений разного уровня (DEBUG, INFO, WARNING, ERROR, CRITICAL), что удобно для поиска нужной информации с применением фильтров.
По умолчанию в logging задан уровень WARNING, это означает, что сообщения уровня DEBUG и INFO будут игнорироваться при записи в лог. Изменить данное поведение можно с помощью метода setLevel, передав минимальный уровень, который будет отлавливаться.
Для отправки логов в сконфигурированные места используются обработчики. Мы можем использовать уже существующие хэндлеры, либо создать свой класс обработчика, унаследовавшись от базового класса Handler.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2
Пакет со всеми алгоритмами
На днях обнаружил крутой пакет, в котором реализованы практически все алгоритмы, которые можно представить.
Список всех алгоритмов с ссылками на их исходный код можете найти здесь. Такой пакет можно использовать и на практике, и как справочник на всякий случай.
Например, можете посмотреть пример использования сортировки слиянием на картинке выше.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
На днях обнаружил крутой пакет, в котором реализованы практически все алгоритмы, которые можно представить.
Список всех алгоритмов с ссылками на их исходный код можете найти здесь. Такой пакет можно использовать и на практике, и как справочник на всякий случай.
Например, можете посмотреть пример использования сортировки слиянием на картинке выше.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3
♾️ Бесконечные аргументы: Магия Звездочек
Замечали, что в функцию
Как сделать такую же всеядную функцию самому? Нам понадобятся операторы распаковки:
📦 1.
Если поставить одну звездочку перед именем аргумента (обычно называют
Теперь ваша функция может принимать хоть 0, хоть 100 чисел!
🗝️ 2.
Две звездочки (обычно
🔄 Обратная магия: Распаковка
Звездочки работают и "на выход"! Если у вас есть список, и вы хотите передать его содержимое как отдельные аргументы:
⚠️ Важно: Порядок в определении функции строгий!
1. Обычные аргументы (
2.
3.
Используйте это, чтобы писать гибкий код, который не нужно переписывать при каждом новом параметре! 😉
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Замечали, что в функцию
print() можно передать сколько угодно значений?print(1, "a", [1,2], True) - и она не ломается!Как сделать такую же всеядную функцию самому? Нам понадобятся операторы распаковки:
* и **.📦 1.
*args (Позиционные аргументы)Если поставить одну звездочку перед именем аргумента (обычно называют
args), Python соберет все переданные значения в кортеж (tuple).
def sum_all(*args):
# args превратится в (1, 2, 3, 4, 5)
print(f"Тип: {type(args)}")
return sum(args)
print(sum_all(1, 2, 3, 4, 5))
# Вывод: 15
Теперь ваша функция может принимать хоть 0, хоть 100 чисел!
🗝️ 2.
**kwargs (Именованные аргументы)Две звездочки (обычно
kwargs - keyword arguments) собирают всё в словарь (dict). Это идеально для настроек или сложных объектов.
def create_profile(**kwargs):
# kwargs превратится в {'name': 'Alex', 'age': 25}
for key, value in kwargs.items():
print(f"{key}: {value}")
create_profile(name="Alex", age=25, city="Minsk")
🔄 Обратная магия: Распаковка
Звездочки работают и "на выход"! Если у вас есть список, и вы хотите передать его содержимое как отдельные аргументы:
numbers = [1, 2, 3]
# Вместо print(numbers[0], numbers[1], numbers[2])
# Пишем просто:
print(*numbers)
# Вывод: 1 2 3
⚠️ Важно: Порядок в определении функции строгий!
1. Обычные аргументы (
a, b)2.
*args3.
**kwargsИспользуйте это, чтобы писать гибкий код, который не нужно переписывать при каждом новом параметре! 😉
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
❤6👍4
Как найти индексы всех вхождений элемента в списке
А что, если искомое значение встречается в списке несколько раз и мы хотим узнать индексы всех этих элементов? Метод index() выдаст нам индекс только первого вхождения.
В этом фрагменте кода мы перебираем индексы списка в цикле for и при помощи range(). Далее мы проверяем значение элемента под каждым индексом на равенство «Math«. Если значение элемента — «Math«, мы сохраняем значение индекса в списке.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
А что, если искомое значение встречается в списке несколько раз и мы хотим узнать индексы всех этих элементов? Метод index() выдаст нам индекс только первого вхождения.
В этом фрагменте кода мы перебираем индексы списка в цикле for и при помощи range(). Далее мы проверяем значение элемента под каждым индексом на равенство «Math«. Если значение элемента — «Math«, мы сохраняем значение индекса в списке.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2
Как искать индекс элемента, которого, возможно, нет в списке
Бывает, нужно получить индекс элемента, но мы не уверены, есть ли он в списке.
Если попытаться получить индекс элемента, которого нет в списке, метод index() вызовет ошибку ValueError. При отсутствии обработки исключений ValueError вызовет аварийное завершение программы. Такой исход явно не является хорошим и с ним нужно что-то сделать.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Бывает, нужно получить индекс элемента, но мы не уверены, есть ли он в списке.
Если попытаться получить индекс элемента, которого нет в списке, метод index() вызовет ошибку ValueError. При отсутствии обработки исключений ValueError вызовет аварийное завершение программы. Такой исход явно не является хорошим и с ним нужно что-то сделать.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍3
Проверка истинности объекта класса
Для того, чтобы определить поведение при проверке на истинность объектов классов в python3 есть "магический" метод __bool__(), который был добавлен на замену устаревшему __nonzero__() в python2.
Если данный метод определен в классе, то он будет вызываться при каждой проверке объекта на истинность а также с помощью функции bool(). Метод должен возвращать False или True.
Если __bool__() не определен, будет вызываться метод __len__(), если он определен, и, соответственно, объект будет считаться истинным, если результат __len__() не будет равен нулю. Если в классе не определены ни __len__(), ни __bool__(), все его экземпляры будут истинными.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Для того, чтобы определить поведение при проверке на истинность объектов классов в python3 есть "магический" метод __bool__(), который был добавлен на замену устаревшему __nonzero__() в python2.
Если данный метод определен в классе, то он будет вызываться при каждой проверке объекта на истинность а также с помощью функции bool(). Метод должен возвращать False или True.
Если __bool__() не определен, будет вызываться метод __len__(), если он определен, и, соответственно, объект будет считаться истинным, если результат __len__() не будет равен нулю. Если в классе не определены ни __len__(), ни __bool__(), все его экземпляры будут истинными.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2
В чем сложность массивов и хешмапов в python
Сложность массивов (списков) и хешмапов (словари) в Python зависит от операций, которые вы выполняете. Вот основные операции и их временные сложности:
Массивы (списки)
В Python массивы представлены списками (`list`). Сложность операций со списками зависит от конкретного действия:
- Доступ по индексу: O(1) — доступ к элементу списка по индексу выполняется за постоянное время, так как список реализован как динамический массив.
- Добавление элемента:
- В конец списка: O(1) амортизированное — добавление элемента в конец списка обычно занимает постоянное время, так как динамический массив увеличивает свой размер экспоненциально.
- В начало или середину списка: O(n) — если вы добавляете элемент в начало или в середину списка, это требует сдвига всех последующих элементов, что занимает линейное время.
- Удаление элемента:
- Из конца списка: O(1) — удаление последнего элемента занимает постоянное время.
- Из начала или середины списка: O(n) — удаление элемента требует сдвига оставшихся элементов.
- Поиск элемента: O(n) — поиск элемента в списке требует обхода всего списка в худшем случае.
Хешмапы (словари)
Хешмапы в Python реализованы с помощью словарей (`dict`). Они используют хеширование для обеспечения быстрого доступа к элементам по ключу:
- Доступ по ключу: O(1) — доступ к элементу по ключу выполняется за постоянное время благодаря хешированию.
- Добавление элемента: O(1) — добавление нового элемента выполняется за постоянное время, если не происходит коллизий.
- Удаление элемента: O(1) — удаление элемента по ключу также выполняется за постоянное время.
- Поиск по ключу: O(1) — поиск элемента по ключу занимает постоянное время.
Сравнение
- Списки полезны, когда важен порядок элементов и доступ к ним по индексу. Однако некоторые операции (например, вставка или удаление в середине списка) могут быть медленными из-за необходимости сдвига элементов.
- Словари обеспечивают быстрый доступ к элементам по ключу, что делает их более эффективными для операций, связанных с поиском и манипуляцией данных по ключу.
Таким образом, основная сложность использования списков и словарей в Python связана с выбором правильной структуры данных для конкретной задачи, чтобы минимизировать временные затраты на ключевые операции.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Сложность массивов (списков) и хешмапов (словари) в Python зависит от операций, которые вы выполняете. Вот основные операции и их временные сложности:
Массивы (списки)
В Python массивы представлены списками (`list`). Сложность операций со списками зависит от конкретного действия:
- Доступ по индексу: O(1) — доступ к элементу списка по индексу выполняется за постоянное время, так как список реализован как динамический массив.
- Добавление элемента:
- В конец списка: O(1) амортизированное — добавление элемента в конец списка обычно занимает постоянное время, так как динамический массив увеличивает свой размер экспоненциально.
- В начало или середину списка: O(n) — если вы добавляете элемент в начало или в середину списка, это требует сдвига всех последующих элементов, что занимает линейное время.
- Удаление элемента:
- Из конца списка: O(1) — удаление последнего элемента занимает постоянное время.
- Из начала или середины списка: O(n) — удаление элемента требует сдвига оставшихся элементов.
- Поиск элемента: O(n) — поиск элемента в списке требует обхода всего списка в худшем случае.
Хешмапы (словари)
Хешмапы в Python реализованы с помощью словарей (`dict`). Они используют хеширование для обеспечения быстрого доступа к элементам по ключу:
- Доступ по ключу: O(1) — доступ к элементу по ключу выполняется за постоянное время благодаря хешированию.
- Добавление элемента: O(1) — добавление нового элемента выполняется за постоянное время, если не происходит коллизий.
- Удаление элемента: O(1) — удаление элемента по ключу также выполняется за постоянное время.
- Поиск по ключу: O(1) — поиск элемента по ключу занимает постоянное время.
Сравнение
- Списки полезны, когда важен порядок элементов и доступ к ним по индексу. Однако некоторые операции (например, вставка или удаление в середине списка) могут быть медленными из-за необходимости сдвига элементов.
- Словари обеспечивают быстрый доступ к элементам по ключу, что делает их более эффективными для операций, связанных с поиском и манипуляцией данных по ключу.
Таким образом, основная сложность использования списков и словарей в Python связана с выбором правильной структуры данных для конкретной задачи, чтобы минимизировать временные затраты на ключевые операции.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2
📝 Код понятный без слов: Аннотации типов
Python - язык с динамической типизацией. Это значит, что переменная
Удобно? Да. Опасно? Еще как! 💣
Представьте функцию:
Что такое
• Если число
• Если строка
• Если список
Чтобы не гадать, используйте Аннотации типов (Type Hints).
✅ Как это выглядит:
🚀 Зачем это нужно?
1. Автодополнение (IDE): Ваш редактор (PyCharm, VS Code) сразу поймет, что
2. Документация: Коллегам не нужно читать весь код функции, чтобы понять, что в неё передавать.
3. Поиск ошибок: Инструменты вроде
💡 Продвинутый уровень (Python 3.10+):
Можно указывать сложные структуры.
⚠️ Важно: Python игнорирует аннотации при запуске! Это просто "подсказки". Если вы напишете
Начните добавлять типы в свои функции, и вы увидите, насколько удобнее станет писать код! 😎
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Python - язык с динамической типизацией. Это значит, что переменная
x может сначала быть числом 5, а через секунду стать строкой "Привет".Удобно? Да. Опасно? Еще как! 💣
Представьте функцию:
def process(data):
return data * 2
Что такое
data? Число? Строка? Список?• Если число
10 -> вернет 20.• Если строка
"Hi" -> вернет "HiHi".• Если список
[1] -> вернет [1, 1].Чтобы не гадать, используйте Аннотации типов (Type Hints).
✅ Как это выглядит:
# Аргумент name - строка, возраст - число
# Функция возвращает строку (-> str)
def greeting(name: str, age: int) -> str:
return f"Привет, {name}! Тебе {age} лет."
🚀 Зачем это нужно?
1. Автодополнение (IDE): Ваш редактор (PyCharm, VS Code) сразу поймет, что
name - это строка, и предложит методы .upper(), .split() и т.д. Без аннотаций он будет "слепым".2. Документация: Коллегам не нужно читать весь код функции, чтобы понять, что в неё передавать.
3. Поиск ошибок: Инструменты вроде
mypy проверят код до запуска и скажут: "Эй, ты пытаешься передать число в функцию, которая ждет строку!"💡 Продвинутый уровень (Python 3.10+):
Можно указывать сложные структуры.
# Список чисел
def sum_list(numbers: list[int]) -> int:
return sum(numbers)
# Или число, ИЛИ строка (Union)
def magic(val: int | str):
print(val)
⚠️ Важно: Python игнорирует аннотации при запуске! Это просто "подсказки". Если вы напишете
x: int, но передадите строку, программа запустится (и, скорее всего, упадет с ошибкой внутри). Аннотации это для вас и редактора, а не для интерпретатора.Начните добавлять типы в свои функции, и вы увидите, насколько удобнее станет писать код! 😎
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
❤4👍4
Как использовать ключевое слово global в Python
По умолчанию Python думает, что внутри функции вы хотите использовать локальную переменную.
И когда мы сначала пытаемся вывести значение переменной, а затем повторно присваиваем значение переменной, к которой мы пытаемся получить доступ, Python запутывается.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
По умолчанию Python думает, что внутри функции вы хотите использовать локальную переменную.
И когда мы сначала пытаемся вывести значение переменной, а затем повторно присваиваем значение переменной, к которой мы пытаемся получить доступ, Python запутывается.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2
Как удалить ключ из словаря при помощи генератора
Генераторы словаря в Python — это быстрые однострочники, которые позволяют легко создавать словари.
Здесь важно понимать, что мы создаем новый словарь. Поэтому это не самый экономичный метод удаления ключа. Но если вы уверены, что ключ существует, а словарь не слишком велик, можно воспользоваться и генератором.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Генераторы словаря в Python — это быстрые однострочники, которые позволяют легко создавать словари.
Здесь важно понимать, что мы создаем новый словарь. Поэтому это не самый экономичный метод удаления ключа. Но если вы уверены, что ключ существует, а словарь не слишком велик, можно воспользоваться и генератором.
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍2