🛠 Передаем параметры красиво
Частая ошибка новичков, склеивать параметры запроса вручную прямо в URL.
❌ Как НЕ надо делать:
✅ Как НАДО делать:
Используйте аргумент
Это делает код чище, безопаснее и профессиональнее. 😎
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Частая ошибка новичков, склеивать параметры запроса вручную прямо в URL.
❌ Как НЕ надо делать:
user_id = 12
# Плохо: сложно читать, легко ошибиться, проблемы со спецсимволами
url = "https://jsonplaceholder.typicode.com/posts?userId=" + str(user_id)
r = requests.get(url)
✅ Как НАДО делать:
Используйте аргумент
params. Библиотека сама всё склеит и, что важно, правильно закодирует символы (например, заменит пробелы на %20).
import requests
url = "https://jsonplaceholder.typicode.com/posts"
# Параметры кладем в словарь
my_params = {
"userId": 1,
"_limit": 5
}
# Передаем словарь в функцию
response = requests.get(url, params=my_params)
print(response.url)
# Вывод: .../posts?userId=1&_limit=5
Это делает код чище, безопаснее и профессиональнее. 😎
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
❤6👍1
🚀 Ускоряем массовые запросы: Sessions
Представьте, что вам нужно скачать 100 страниц сайта. Если делать это через обычный
1. Открытие соединения (TCP Handshake).
2. Настройка шифрования (SSL/TLS).
3. Отправка данных.
4. Закрытие соединения.
Это очень долго! 🐢
Решение: Session
Сессия позволяет переиспользовать одно и то же соединение для множества запросов. Это дает огромный прирост скорости.
Пример:
💡Сессия также запоминает куки (cookies). Если вы авторизовались на сайте в первом запросе, сессия "запомнит" это для следующих.
Используйте сессии, если делаете больше двух запросов к одному сайту!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
Представьте, что вам нужно скачать 100 страниц сайта. Если делать это через обычный
requests.get(), каждый раз будет происходить следующее:1. Открытие соединения (TCP Handshake).
2. Настройка шифрования (SSL/TLS).
3. Отправка данных.
4. Закрытие соединения.
Это очень долго! 🐢
Решение: Session
Сессия позволяет переиспользовать одно и то же соединение для множества запросов. Это дает огромный прирост скорости.
Пример:
import requests
# Создаем сессию
with requests.Session() as s:
# Можно сразу настроить заголовки для всех запросов
s.headers.update({'User-Agent': 'my-app/0.0.1'})
for i in range(5):
# Используем s.get вместо requests.get
r = s.get(f"https://httpbin.org/get?page={i}")
print(f"Запрос {i} выполнен!")
💡Сессия также запоминает куки (cookies). Если вы авторизовались на сайте в первом запросе, сессия "запомнит" это для следующих.
Используйте сессии, если делаете больше двух запросов к одному сайту!
📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
👍4
🛑 Твой код завис навсегда? Исправляем!
Знаете ли вы, что по умолчанию библиотека
Если сервер, к которому вы обращаетесь, "упал" или просто завис, ваш 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