Создание коротких ссылок с использованием стороннего API
Длинные URL — зло. Их неудобно отправлять в мессенджерах, сложно запоминать, а выглядят они как случайный набор символов. Давай сделаем свой мини‑«сократитель ссылок» на Python, используя сторонний API.
В качестве примера возьмем бесплатный сервис shrtco.de. Он предоставляет простой HTTP‑API для сокращения ссылок.
---
### Что нам понадобится
1. Модуль
2. Любая обычная ссылка, которую нужно сократить.
Установим
---
### Базовый пример: сокращаем одну ссылку
Что здесь происходит:
-
-
- Из поля
---
### Обработка ошибок и проверка входных данных
Интернет не идеален: иногда API падает, иногда пользователь передает ерунду вместо ссылки. Добавим простую обертку с обработкой ошибок:
---
### Мини‑утилита для списка ссылок
Теперь сделаем маленький скрипт, который умеет сокращать несколько ссылок сразу:
Так можно быстро подготовить короткие ссылки, например, для рассылки или описания проекта.
---
В итоге ты познакомился с базовой схемой работы с внешним API: отправили запрос, получили JSON, вытащили нужные поля, обработали ошибки. Дальше можно развивать идею: сделать CLI‑утилиту, интеграцию в телеграм‑бота или даже собственную веб‑страницу‑сократитель на Flask или FastAPI.
Длинные URL — зло. Их неудобно отправлять в мессенджерах, сложно запоминать, а выглядят они как случайный набор символов. Давай сделаем свой мини‑«сократитель ссылок» на Python, используя сторонний API.
В качестве примера возьмем бесплатный сервис shrtco.de. Он предоставляет простой HTTP‑API для сокращения ссылок.
---
### Что нам понадобится
1. Модуль
requests для отправки HTTP‑запросов.2. Любая обычная ссылка, которую нужно сократить.
Установим
requests (если еще не установлен):pip install requests
---
### Базовый пример: сокращаем одну ссылку
import requests
def shorten_url(long_url: str) -> str:
api_url = "https://api.shrtco.de/v2/shorten"
params = {"url": long_url}
response = requests.get(api_url, params=params, timeout=10)
response.raise_for_status() # выбросит исключение, если статус не 200
data = response.json()
if not data.get("ok"):
raise ValueError(f"API error: {data}")
return data["result"]["full_short_link"]
if __name__ == "__main__":
long_url = "https://www.python.org/doc/"
short_url = shorten_url(long_url)
print(f"Original: {long_url}")
print(f"Short: {short_url}")
Что здесь происходит:
-
requests.get отправляет GET‑запрос на API.-
response.json() превращает ответ сервера в словарь Python.- Из поля
result["full_short_link"] берем уже готовую короткую ссылку.---
### Обработка ошибок и проверка входных данных
Интернет не идеален: иногда API падает, иногда пользователь передает ерунду вместо ссылки. Добавим простую обертку с обработкой ошибок:
def safe_shorten_url(long_url: str) -> str:
if not long_url.startswith(("http://", "https://")):
raise ValueError("URL must start with http:// or https://")
try:
return shorten_url(long_url)
except requests.exceptions.RequestException as e:
print(f"Network error: {e}")
return long_url # в худшем случае вернем исходный URL
except ValueError as e:
print(f"API responded with error: {e}")
return long_url
---
### Мини‑утилита для списка ссылок
Теперь сделаем маленький скрипт, который умеет сокращать несколько ссылок сразу:
def batch_shorten(urls: list[str]) -> dict[str, str]:
result = {}
for url in urls:
short = safe_shorten_url(url)
result[url] = short
return result
if __name__ == "__main__":
urls = [
"https://docs.python.org/3/library/",
"https://pypi.org/project/requests/",
"https://www.djangoproject.com/",
]
mapping = batch_shorten(urls)
for original, short in mapping.items():
print(f"{original} -> {short}")
Так можно быстро подготовить короткие ссылки, например, для рассылки или описания проекта.
---
В итоге ты познакомился с базовой схемой работы с внешним API: отправили запрос, получили JSON, вытащили нужные поля, обработали ошибки. Дальше можно развивать идею: сделать CLI‑утилиту, интеграцию в телеграм‑бота или даже собственную веб‑страницу‑сократитель на Flask или FastAPI.
👍3
Как создать простую капчу с помощью библиотеки
Капча — это маленький страж, который защищает формы на сайте от ботов: регистрация, вход, отправка заявки. Давай разберёмся, как всего за несколько строк на Python сделать свою простую капчу в виде картинки с текстом.
### Установка библиотеки
Нам понадобится модуль
Основной класс, с которым будем работать, —
### Генерация изображения капчи
Сгенерируем картинку с кодом и сохраним её в файл:
Что здесь происходит:
-
-
- Картинка сохраняется как
### Проверка ответа пользователя
Обычно логика следующая: мы генерируем капчу, сохраняем код в сессии (или временно в памяти), затем сравниваем его с вводом пользователя.
Упрощённый пример без веб-фреймворка:
### Идеи для улучшения
- Увеличить длину кода (
- Генерировать разные размеры картинок (
- Хранить коды не в памяти, а, например, в Redis или сессии веб-фреймворка.
Такая капча не заменит сложные промышленные решения, но для учебных проектов, pet-проектов и внутренних инструментов этого более чем достаточно и прекрасно показывает связку: генерация данных → создание изображения → валидация ввода пользователя.
captchaКапча — это маленький страж, который защищает формы на сайте от ботов: регистрация, вход, отправка заявки. Давай разберёмся, как всего за несколько строк на Python сделать свою простую капчу в виде картинки с текстом.
### Установка библиотеки
Нам понадобится модуль
captcha:pip install captcha
Основной класс, с которым будем работать, —
ImageCaptcha.### Генерация изображения капчи
Сгенерируем картинку с кодом и сохраним её в файл:
from captcha.image import ImageCaptcha
import random
import string
def generate_code(length: int = 5) -> str:
symbols = string.ascii_uppercase + string.digits
return ''.join(random.choice(symbols) for _ in range(length))
def generate_captcha(image_path: str = "captcha.png") -> str:
image_captcha = ImageCaptcha(width=200, height=80)
code = generate_code()
image = image_captcha.generate_image(code)
image.save(image_path)
return code
if __name__ == "__main__":
correct_code = generate_captcha()
print("Captcha code:", correct_code)
Что здесь происходит:
-
generate_code создаёт случайный набор из букв и цифр.-
ImageCaptcha рисует картинку с этим кодом.- Картинка сохраняется как
captcha.png, а правильный код возвращается для дальнейшей проверки.### Проверка ответа пользователя
Обычно логика следующая: мы генерируем капчу, сохраняем код в сессии (или временно в памяти), затем сравниваем его с вводом пользователя.
Упрощённый пример без веб-фреймворка:
def verify_captcha(user_input: str, correct_code: str) -> bool:
return user_input.strip().upper() == correct_code.upper()
if __name__ == "__main__":
correct_code = generate_captcha()
user_input = input("Enter captcha from image: ")
if verify_captcha(user_input, correct_code):
print("Access granted")
else:
print("Access denied")
### Идеи для улучшения
- Увеличить длину кода (
length=6–7), чтобы усложнить перебор.- Генерировать разные размеры картинок (
width, height) под дизайн сайта.- Хранить коды не в памяти, а, например, в Redis или сессии веб-фреймворка.
Такая капча не заменит сложные промышленные решения, но для учебных проектов, pet-проектов и внутренних инструментов этого более чем достаточно и прекрасно показывает связку: генерация данных → создание изображения → валидация ввода пользователя.
👍3
Реализация счетчика посещений сайта на Flask и SQLite
Иногда самый полезный функционал — самый простой. Счётчик посещений показывает, что сайт “живой”: им пользуются, к нему возвращаются. Давай сделаем минималистичный, но “правильный” вариант на Flask + SQLite.
### Архитектура идеи
Нам нужно:
1. Веб-приложение на Flask.
2. База данных SQLite с таблицей
3. Логика: при заходе на страницу увеличиваем число посещений и показываем пользователю.
Почему SQLite?
- Ничего устанавливать отдельно не нужно — база хранится в одном файле.
- Для маленьких проектов и пет-проектов более чем достаточно.
### Создаём базу и таблицу
Файл
Этот скрипт:
- создаёт файл
- гарантирует единственную строку с
Запусти его один раз:
### Flask-приложение
Файл
Что здесь важно:
- Отдельная функция
-
- В
### Возможные улучшения
- Сохранять IP пользователя, User-Agent и дату визита в отдельной таблице
- Добавить отдельную админ-страницу
- Вынести конфиг базы и пути в отдельный файл настроек.
С таким минимальным примером у тебя уже есть полноценный счётчик посещений, который не сбросится при перезапуске сервера и не зависит от сторонних сервисов.
Иногда самый полезный функционал — самый простой. Счётчик посещений показывает, что сайт “живой”: им пользуются, к нему возвращаются. Давай сделаем минималистичный, но “правильный” вариант на Flask + SQLite.
### Архитектура идеи
Нам нужно:
1. Веб-приложение на Flask.
2. База данных SQLite с таблицей
visits. 3. Логика: при заходе на страницу увеличиваем число посещений и показываем пользователю.
Почему SQLite?
- Ничего устанавливать отдельно не нужно — база хранится в одном файле.
- Для маленьких проектов и пет-проектов более чем достаточно.
### Создаём базу и таблицу
Файл
init_db.py:import sqlite3
def init_db():
conn = sqlite3.connect("stats.db")
cursor = conn.cursor()
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS visits (
id INTEGER PRIMARY KEY CHECK (id = 1),
counter INTEGER NOT NULL
)
"""
)
cursor.execute("INSERT OR IGNORE INTO visits (id, counter) VALUES (1, 0)")
conn.commit()
conn.close()
if __name__ == "__main__":
init_db()
Этот скрипт:
- создаёт файл
stats.db,- гарантирует единственную строку с
id = 1, где живёт наш счётчик.Запусти его один раз:
python init_db.py.### Flask-приложение
Файл
app.py:from flask import Flask
import sqlite3
app = Flask(__name__)
def get_db_connection():
conn = sqlite3.connect("stats.db")
conn.row_factory = sqlite3.Row
return conn
def increment_counter():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("UPDATE visits SET counter = counter + 1 WHERE id = 1")
conn.commit()
cursor.execute("SELECT counter FROM visits WHERE id = 1")
row = cursor.fetchone()
conn.close()
return row["counter"]
@app.route("/")
def index():
visits = increment_counter()
return f"<h1>Welcome!</h1><p>This page was visited {visits} times.</p>"
if __name__ == "__main__":
app.run(debug=True)
Что здесь важно:
- Отдельная функция
get_db_connection() — хороший тон, код легче масштабировать.-
increment_counter() инкапсулирует всю работу с базой: обновление и чтение.- В
index() мы просто вызываем логику и выводим результат.### Возможные улучшения
- Сохранять IP пользователя, User-Agent и дату визита в отдельной таблице
visits_log.- Добавить отдельную админ-страницу
/stats, где показывать не только общее число, но и статистику по дням.- Вынести конфиг базы и пути в отдельный файл настроек.
С таким минимальным примером у тебя уже есть полноценный счётчик посещений, который не сбросится при перезапуске сервера и не зависит от сторонних сервисов.
🔥4
Сравнение объектов в Python: магия
Пока мы сравниваем только числа и строки, все просто:
---
### Базовое сравнение: что делает Python по умолчанию
Если у класса не определен
---
### Даем объектам смысл: реализуем
Сделаем так, чтобы точки считались равными, если равны их координаты:
Ключевой момент — возвращать
---
### Порядок имеет значение: реализуем
Метод
Теперь
---
###
Если реализовать все сравнения вручную (
Достаточно реализовать
---
### Итог
1. По умолчанию объекты сравниваются по идентичности, а не по содержимому.
2.
3. Возвращайте
4. Используйте
Когда объекты начинают “понимать”, как им сравниваться, код становится проще, а данные — значительно умнее.
__eq__ и __lt__Пока мы сравниваем только числа и строки, все просто:
==, <, >, и жизнь удалась. Проблемы начинаются, когда у нас появляются собственные классы: User, Order, Point и т.д. Как Python должен решать, что два объекта равны? Или какой из них “меньше”? По умолчанию — никак полезно для нас.---
### Базовое сравнение: что делает Python по умолчанию
Если у класса не определен
__eq__, выражение a == b для двух объектов одного класса проверяет, один и тот же ли это объект в памяти. Два разных, но “по смыслу” одинаковых объекта будут считаться неравными:class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # False
---
### Даем объектам смысл: реализуем
__eq__Сделаем так, чтобы точки считались равными, если равны их координаты:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return (self.x, self.y) == (other.x, other.y)
p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(2, 3)
print(p1 == p2) # True
print(p1 == p3) # False
Ключевой момент — возвращать
NotImplemented, если объект другого типа. Тогда Python попробует обратное сравнение или корректно вернёт False.---
### Порядок имеет значение: реализуем
__lt__Метод
__lt__ (“less than”) нужен для операторов < и для сортировки. Например, хотим сортировать точки по расстоянию от начала координат:import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self):
return math.hypot(self.x, self.y)
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
def __lt__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.distance() < other.distance()
points = [Point(3, 4), Point(1, 1), Point(0, 5)]
points.sort()
for p in points:
print(p.x, p.y)
Теперь
sort() понимает, как сравнивать объекты Point.---
###
functools.total_ordering: меньше кода – больше порядкаЕсли реализовать все сравнения вручную (
__lt__, __le__, __gt__, __ge__), код раздуется. Модуль functools умеет помочь:from functools import total_ordering
import math
@total_ordering
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self):
return math.hypot(self.x, self.y)
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return (self.x, self.y) == (other.x, other.y)
def __lt__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.distance() < other.distance()
Достаточно реализовать
__eq__ и один из методов порядка (__lt__, __le__, __gt__ или __ge__) — остальные создат total_ordering.---
### Итог
1. По умолчанию объекты сравниваются по идентичности, а не по содержимому.
2.
__eq__ отвечает за смысл равенства, __lt__ — за порядок (и сортировку). 3. Возвращайте
NotImplemented при сравнении с чужими типами. 4. Используйте
functools.total_ordering, чтобы не писать все методы сравнения вручную.Когда объекты начинают “понимать”, как им сравниваться, код становится проще, а данные — значительно умнее.
👍3❤1
Python для начинающих: узнаём имя компьютера, IP и ОС
Иногда хочется, чтобы программа знала, где она вообще запущена: как зовут компьютер, какой у него IP-адрес и под какой ОС всё это работает. Это важно для логирования, сетевых скриптов, настройки путей и просто для самодиагностики.
Сегодня разберём три стандартных модуля:
---
## Имя компьютера и IP-адрес
Модуль
Проблема:
Интернет реально не используется, но сокету нужно «представиться» и он раскрывает наш реальный адрес в сети.
---
## Определяем операционную систему
Здесь король — модуль
Если нужна «человеческая» строка одним махом:
---
## Немного о пользователе и окружении
Модуль
---
## Собираем всё вместе
Мини-скрипт системной самодиагностики:
Такой скрипт можно встроить в любой проект: логировать среду запуска, подстраивать поведение под ОС или просто использовать как первый шаг к более серьёзным инструментам администрирования и мониторинга.
Иногда хочется, чтобы программа знала, где она вообще запущена: как зовут компьютер, какой у него IP-адрес и под какой ОС всё это работает. Это важно для логирования, сетевых скриптов, настройки путей и просто для самодиагностики.
Сегодня разберём три стандартных модуля:
socket, platform и os. Никаких сторонних библиотек, всё есть «из коробки».---
## Имя компьютера и IP-адрес
Модуль
socket умеет работать с сетью и при этом спокойно подскажет, как зовут машину и какой у неё IP.import socket
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
print(f"Hostname: {hostname}")
print(f"IP address: {ip_address}")
Проблема:
gethostbyname иногда возвращает 127.0.0.1, если система так настроена. Более надёжный способ — открыть «фальшивое» соединение наружу и посмотреть, с какого адреса мы выходим:import socket
def get_local_ip():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
print("Local IP:", get_local_ip())
Интернет реально не используется, но сокету нужно «представиться» и он раскрывает наш реальный адрес в сети.
---
## Определяем операционную систему
Здесь король — модуль
platform. Он даёт как короткую, так и детальную информацию.import platform
print("System:", platform.system()) # 'Windows', 'Linux', 'Darwin'
print("Release:", platform.release()) # версия системы
print("Version:", platform.version()) # детальная строка
print("Machine:", platform.machine()) # архитектура (x86_64, arm64...)
Если нужна «человеческая» строка одним махом:
import platform
info = platform.platform()
print("Platform info:", info)
---
## Немного о пользователе и окружении
Модуль
os помогает заглянуть в окружение: путь к пользователю, имя юзера и прочие системные переменные.import os
user = os.getenv("USERNAME") or os.getenv("USER")
home_dir = os.path.expanduser("~")
print(f"User: {user}")
print(f"Home directory: {home_dir}")
---
## Собираем всё вместе
Мини-скрипт системной самодиагностики:
import socket
import platform
import os
def get_local_ip():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
def get_system_info():
hostname = socket.gethostname()
ip_address = get_local_ip()
system = platform.system()
release = platform.release()
user = os.getenv("USERNAME") or os.getenv("USER")
return {
"hostname": hostname,
"ip": ip_address,
"system": system,
"release": release,
"user": user,
}
if __name__ == "__main__":
info = get_system_info()
for key, value in info.items():
print(f"{key}: {value}")
Такой скрипт можно встроить в любой проект: логировать среду запуска, подстраивать поведение под ОС или просто использовать как первый шаг к более серьёзным инструментам администрирования и мониторинга.
👍5
Создание текстовых отчетов и логов с записью в файл день за днем
Рано или поздно любой скрипт вырастает до состояния: «Хочу понимать, что он делал вчера ночью». Тут на сцену выходят отчеты и логи. Давайте разберем пару рабочих приемов: ежедневные файлы логов и простые текстовые отчеты.
---
## Ежедневный лог-файл
Частая практика — один файл лога на день:
Сделаем простую функцию-логгер:
Что здесь важно:
-
- Режим
- Имя файла зависит от даты — архив логов сам формируется по дням.
---
## Простой текстовый отчет по результатам работы
Представим скрипт, который что-то обрабатывает и в конце дня создает итоговый отчет: сколько задач прошло, сколько упало, какой процент успеха.
Фишки:
- Отчет — обычный текстовый файл, его легко открыть в любом редакторе или отправить по почте.
- Формат предельно простой, но уже дает картину дня.
- Логгер и отчет связаны: лог фиксирует факт создания отчета.
---
## Идея для развития
Дальше можно:
- добавлять в отчет «ТОП-5 ошибок дня»;
- архивировать старые логи в zip;
- использовать модуль
Но фундамент один: аккуратная, ежедневная запись в файлы с понятными именами и структурой. Это уже делает ваш код ближе к «боевому» уровню.
Рано или поздно любой скрипт вырастает до состояния: «Хочу понимать, что он делал вчера ночью». Тут на сцену выходят отчеты и логи. Давайте разберем пару рабочих приемов: ежедневные файлы логов и простые текстовые отчеты.
---
## Ежедневный лог-файл
Частая практика — один файл лога на день:
log_2025-01-21.txt, log_2025-01-22.txt и т.д. Сделаем простую функцию-логгер:
from datetime import datetime
from pathlib import Path
LOG_DIR = Path("logs")
LOG_DIR.mkdir(exist_ok=True)
def get_log_file_path() -> Path:
today_str = datetime.now().strftime("%Y-%m-%d")
return LOG_DIR / f"log_{today_str}.txt"
def log_message(level: str, message: str) -> None:
log_file = get_log_file_path()
time_str = datetime.now().strftime("%H:%M:%S")
line = f"[{time_str}] [{level.upper()}] {message}\n"
with log_file.open("a", encoding="utf-8") as f:
f.write(line)
# Пример использования
log_message("info", "Script started")
log_message("warning", "Low disk space")
log_message("error", "Failed to connect to server")
Что здесь важно:
-
Path из pathlib удобнее обычных строк для путей.- Режим
"a" — дозапись в конец файла, не стирая старые логи.- Имя файла зависит от даты — архив логов сам формируется по дням.
---
## Простой текстовый отчет по результатам работы
Представим скрипт, который что-то обрабатывает и в конце дня создает итоговый отчет: сколько задач прошло, сколько упало, какой процент успеха.
from datetime import datetime
from pathlib import Path
REPORT_DIR = Path("reports")
REPORT_DIR.mkdir(exist_ok=True)
def save_daily_report(total: int, success: int, failed: int) -> Path:
today_str = datetime.now().strftime("%Y-%m-%d")
report_path = REPORT_DIR / f"report_{today_str}.txt"
success_rate = (success / total * 100) if total else 0
lines = [
f"Report date: {today_str}",
f"Total tasks: {total}",
f"Successful: {success}",
f"Failed: {failed}",
f"Success rate: {success_rate:.2f}%",
]
with report_path.open("w", encoding="utf-8") as f:
f.write("\n".join(lines))
return report_path
# Пример
report_file = save_daily_report(total=120, success=110, failed=10)
log_message("info", f"Daily report saved to {report_file}")
Фишки:
- Отчет — обычный текстовый файл, его легко открыть в любом редакторе или отправить по почте.
- Формат предельно простой, но уже дает картину дня.
- Логгер и отчет связаны: лог фиксирует факт создания отчета.
---
## Идея для развития
Дальше можно:
- добавлять в отчет «ТОП-5 ошибок дня»;
- архивировать старые логи в zip;
- использовать модуль
logging, чтобы прокачать формат и уровни логов.Но фундамент один: аккуратная, ежедневная запись в файлы с понятными именами и структурой. Это уже делает ваш код ближе к «боевому» уровню.
👍3
Изучение
Модуль
Разберём три ключевые группы: комбинации, перестановки и бесконечные итераторы.
---
## Комбинации и перестановки
###
Результат:
Полезно для перебора возможных пар/наборов параметров, команд, вариантов выбора.
###
Здесь и
###
Это быстрый способ перебрать все сочетания параметров при тестировании, конфигурациях и т.п.
---
## Бесконечные итераторы
Иногда удобно иметь “бесконечный источник” данных, который вы сами ограничиваете.
###
###
Получаем повторяющийся цикл состояний, полезно для простых симуляций или циклических индикаторов.
###
В связке с
---
itertools: комбинации, перестановки и бесконечные итераторыМодуль
itertools — это чемоданчик с инструментами для работы с последовательностями. Он не шумит, не требует сложной настройки, но иногда одним-двумя его вызовами можно заменить десяток строк кода с циклами.Разберём три ключевые группы: комбинации, перестановки и бесконечные итераторы.
---
## Комбинации и перестановки
###
combinationscombinations(iterable, r) перебирает все уникальные наборы по r элементов без повторов и без учёта порядка.from itertools import combinations
items = ['a', 'b', 'c', 'd']
for combo in combinations(items, 2):
print(combo)
Результат:
('a', 'b'), ('a', 'c'), ... — но не будет ('b', 'a'), потому что порядок не важен.Полезно для перебора возможных пар/наборов параметров, команд, вариантов выбора.
###
permutationspermutations(iterable, r=None) — все возможные варианты с учётом порядка.from itertools import permutations
letters = ['A', 'B', 'C']
for p in permutations(letters, 2):
print(p)
Здесь и
('A', 'B'), и ('B', 'A') — уже разные результаты. Удобно, когда порядок критичен: генерация пароля, маршрута, очередности задач.###
productproduct — декартово произведение. Можно представить как вложенные циклы.from itertools import product
colors = ['red', 'green']
sizes = ['S', 'M', 'L']
for item in product(colors, sizes):
print(item)
Это быстрый способ перебрать все сочетания параметров при тестировании, конфигурациях и т.п.
---
## Бесконечные итераторы
Иногда удобно иметь “бесконечный источник” данных, который вы сами ограничиваете.
###
countcount(start=0, step=1) — бесконечный счётчик.from itertools import count, islice
for n in islice(count(10, 2), 5):
print(n)
islice здесь обрезает бесконечную последовательность до 5 элементов: 10, 12, 14, 16, 18.###
cyclecycle(iterable) — крутит последовательность по кругу.from itertools import cycle, islice
states = ['loading', 'processing', 'done']
for s in islice(cycle(states), 7):
print(s)
Получаем повторяющийся цикл состояний, полезно для простых симуляций или циклических индикаторов.
###
repeatrepeat(object, times=None) возвращает один и тот же объект много раз.from itertools import repeat
for msg in repeat("ping", 3):
print(msg)
В связке с
map удобно передавать одинаковый аргумент множеству вызовов.---
itertools хорош тем, что он “мысленно сокращает” код: когда вы видите combinations или product, сразу понятно, что именно происходит, без чтения вложенных циклов. Попробуйте заменить пару своих циклов этими функциями — и код станет и короче, и чище.👍3
Pathlib: современный способ подружиться с путями и файлами в Python
Модуль
---
### Создание путей
Оператор
---
### Проверка существования и свойств
---
### Чтение и запись файлов
Для текстовых файлов
Для бинарных данных есть методы
---
### Обход директорий и поиск файлов
---
### Безопасные операции с файлами
---
Модуль
pathlib — это попытка Python сказать: «Хватит мучиться со строками путей и os.path». Он даёт удобный объект Path, который понимает операционные системы, красиво соединяет части пути и умеет работать с файлами почти как с объектами.---
### Создание путей
from pathlib import Path
# Текущая директория
current_dir = Path.cwd()
# Домашняя директория
home_dir = Path.home()
# Относительный путь
project_dir = Path("projects") / "my_app"
# Путь с "магическим" слэшем
config_file = project_dir / "config.yaml"
print(config_file) # projects/my_app/config.yaml (или с \ на Windows)
Оператор
/ — это не деление, а аккуратное склеивание частей пути под вашу ОС.---
### Проверка существования и свойств
from pathlib import Path
path = Path("data/example.txt")
print(path.exists()) # файл или папка существует?
print(path.is_file()) # это файл?
print(path.is_dir()) # это директория?
print(path.parent) # родительская директория
print(path.name) # имя файла с расширением
print(path.stem) # имя без расширения
print(path.suffix) # расширение (.txt)
---
### Чтение и запись файлов
Для текстовых файлов
pathlib даёт очень лаконичный синтаксис:from pathlib import Path
text_file = Path("notes/todo.txt")
# Запись
text_file.parent.mkdir(parents=True, exist_ok=True)
text_file.write_text("Learn pathlib\nUse it everywhere!", encoding="utf-8")
# Чтение
content = text_file.read_text(encoding="utf-8")
print(content)
Для бинарных данных есть методы
write_bytes() и read_bytes().---
### Обход директорий и поиск файлов
from pathlib import Path
logs_dir = Path("logs")
# Все .log-файлы в директории (без поддиректорий)
for log_file in logs_dir.glob("*.log"):
print(log_file)
# Рекурсивно найти все .py-файлы
for py_file in Path(".").rglob("*.py"):
print(py_file)
glob() и rglob() понимают шаблоны (*, ?), так что можно быстро фильтровать нужные файлы.---
### Безопасные операции с файлами
from pathlib import Path
src = Path("data/raw/data.csv")
dst = Path("data/processed/data.csv")
# Создаём директорию, если её нет
dst.parent.mkdir(parents=True, exist_ok=True)
# Переименование или перенос
if src.exists():
src.rename(dst)
---
pathlib заменяет кучу разрозненных функций из os, os.path и shutil единым, логичным интерфейсом. Стоит привыкнуть к Path — и строковые пути начнут казаться пережитком прошлого.👍5
Работа с модулем
Если вы когда‑нибудь пытались “вручную” вычислить день недели или красиво вывести календарь в консоль, то модуль
### Быстрый старт: печатаем календарь месяца
Результат — готовый текстовый календарь марта 2025. Для целого года есть аналог:
Уже можно делать простенькие консольные планировщики.
### Как устроен месяц “внутри”
Чтобы работать с датами программно, удобен метод
Каждая неделя — список из 7 чисел. Нули означают “нет дня” (ячейка принадлежит соседнему месяцу). Это удобно для логики, например, подсветки выходных или праздников.
### Добавляем события в календарь
Сделаем простую текстовую “раскраску” дат с событиями:
Вы увидите сетку чисел, а дни с событиями будут помечены
### Дни недели и “рабочий” календарь
Модуль
Так можно быстро считать количество рабочих дней, искать все пятницы или строить графики дежурств.
### Дополнительно
-
-
-
calendar: удобное отображение дат и событийЕсли вы когда‑нибудь пытались “вручную” вычислить день недели или красиво вывести календарь в консоль, то модуль
calendar создан именно для того, чтобы вы перестали страдать.### Быстрый старт: печатаем календарь месяца
import calendar
year = 2025
month = 3
cal = calendar.month(year, month)
print(cal)
Результат — готовый текстовый календарь марта 2025. Для целого года есть аналог:
print(calendar.calendar(2025))
Уже можно делать простенькие консольные планировщики.
### Как устроен месяц “внутри”
Чтобы работать с датами программно, удобен метод
monthcalendar:import calendar
year = 2025
month = 3
c = calendar.Calendar(firstweekday=0) # 0 – понедельник
month_matrix = c.monthdayscalendar(year, month)
for week in month_matrix:
print(week)
Каждая неделя — список из 7 чисел. Нули означают “нет дня” (ячейка принадлежит соседнему месяцу). Это удобно для логики, например, подсветки выходных или праздников.
### Добавляем события в календарь
Сделаем простую текстовую “раскраску” дат с событиями:
import calendar
events = {
(2025, 3, 8): "Holiday",
(2025, 3, 15): "Deadline",
}
year, month = 2025, 3
c = calendar.Calendar(firstweekday=0)
for week in c.monthdayscalendar(year, month):
line = []
for day in week:
if day == 0:
line.append(" ")
continue
key = (year, month, day)
if key in events:
# отмечаем события звездочкой
line.append(f"{day:2d}*")
else:
line.append(f"{day:2d} ")
print(" ".join(line))
Вы увидите сетку чисел, а дни с событиями будут помечены
*. Такой вывод легко адаптировать под любой интерфейс: консоль, web, GUI.### Дни недели и “рабочий” календарь
Модуль
calendar знает всё о буднях и выходных:import calendar
year, month = 2025, 3
workdays = []
for week in calendar.monthcalendar(year, month):
for i, day in enumerate(week):
if day == 0:
continue
# 0–4: понедельник–пятница
if i < 5:
workdays.append(day)
print("Workdays:", workdays)
Так можно быстро считать количество рабочих дней, искать все пятницы или строить графики дежурств.
### Дополнительно
-
calendar.isleap(year) — проверка високосного года. -
calendar.weekday(year, month, day) — номер дня недели (0 — понедельник). -
setfirstweekday() — глобально изменить первый день недели.calendar — отличный инструмент, чтобы перестать думать о том, на какой день недели падает 1 апреля, и сосредоточиться на логике приложения.👍5
Создание и использование генераторов:
Когда цикл
### Что такое генератор?
Генератор — это объект, который «помнит», где он остановился, и при следующем запросе продолжает с этого места. Создать его можно двумя способами:
1. Функция с ключевым словом
2. Генераторное выражение:
### Простейший пример с
Функция
### Генератор против списка
Оба варианта дадут одинаковый результат, но
### Бесконечные последовательности
Генераторы легко порождают бесконечные последовательности — такое невозможно в виде обычного списка:
Функция никогда не завершится сама, но генератор выдает значения, пока вы их запрашиваете.
### Генераторные выражения
Краткая запись:
Здесь
---
yield в действииКогда цикл
for в Python перебирает список, он хранит весь список в памяти. Удобно, но не всегда эффективно. Генераторы позволяют «лениво» выдавать значения по одному — экономя память и иногда ускоряя код.### Что такое генератор?
Генератор — это объект, который «помнит», где он остановился, и при следующем запросе продолжает с этого места. Создать его можно двумя способами:
1. Функция с ключевым словом
yield2. Генераторное выражение:
(x * 2 for x in range(10))### Простейший пример с
yielddef countdown(n):
while n > 0:
yield n
n -= 1
for number in countdown(5):
print(number)
Функция
countdown не возвращает список. Она каждый раз «выдает» следующее значение через yield. Память тратится только на текущее состояние, а не на весь набор чисел.### Генератор против списка
def squares_list(n):
result = []
for i in range(n):
result.append(i * i)
return result
def squares_gen(n):
for i in range(n):
yield i * i
print(sum(squares_list(10_000_000)))
print(sum(squares_gen(10_000_000)))
Оба варианта дадут одинаковый результат, но
squares_list создаст огромный список в памяти, а squares_gen будет считать по одному значению. Разница станет особенно заметна при больших n или при обработке потоков данных (логов, файлов, сетевых запросов).### Бесконечные последовательности
Генераторы легко порождают бесконечные последовательности — такое невозможно в виде обычного списка:
def infinite_counter(start=0):
current = start
while True:
yield current
current += 1
counter = infinite_counter()
for _ in range(5):
print(next(counter))
Функция никогда не завершится сама, но генератор выдает значения, пока вы их запрашиваете.
### Генераторные выражения
Краткая запись:
evens = (x for x in range(100) if x % 2 == 0)
print(sum(evens))
Здесь
evens — генератор, а не список. Память используется минимально.---
yield — это не просто «альтернатива return». Это способ думать о данных как о потоке значений: не «хранить всё», а «выдавать по запросу». Для обработки больших объемов данных и написания эффективного кода в Python это один из ключевых инструментов.👍5
### Модуль
Когда ваш код “летает”, это приятно. Но иногда нужно не только скорость, но и… паузы. Звучит странно, но без задержек и точного измерения времени не обойтись: от тестирования до симуляции медленных внешних сервисов.
Разберём модуль
---
## Базовая задержка:
Функция
Полезно для:
- имитации долгих операций (запросов к БД, API),
- создания задержек между запросами (во избежание банов),
- тестирования поведения интерфейсов.
---
## Измеряем время выполнения кода
Наивный способ —
Но у этого подхода есть минус: точность зависит от системных часов, которые могут “прыгать”.
---
## Более точный замер:
Для профилирования (измерения скорости) лучше использовать
Используйте
---
## Имитируем “медленный” внешний сервис
Представьте, что вы пишете функцию, которая обращается к API, но настоящего API ещё нет. Можно сделать фейковую задержку:
Так удобно тестировать:
- обработку долгих ответов,
- таймауты,
- индикаторы загрузки.
---
## Мини-профайлер на коленке
Можно написать простый декоратор для измерения времени выполнения любой функции.
Так вы быстро находите “узкие места” без тяжёлых инструментов.
---
Модуль
time: замер и имитация задержек в кодеКогда ваш код “летает”, это приятно. Но иногда нужно не только скорость, но и… паузы. Звучит странно, но без задержек и точного измерения времени не обойтись: от тестирования до симуляции медленных внешних сервисов.
Разберём модуль
time: как измерять выполнение кода и как “тормозить” программу по собственному желанию.---
## Базовая задержка:
time.sleepФункция
sleep просто приостанавливает выполнение программы на указанное число секунд (можно дробное).import time
print("Start")
time.sleep(2.5) # пауза 2.5 секунды
print("End")
Полезно для:
- имитации долгих операций (запросов к БД, API),
- создания задержек между запросами (во избежание банов),
- тестирования поведения интерфейсов.
---
## Измеряем время выполнения кода
Наивный способ —
time.time(). Он возвращает текущее время в секундах с начала эпохи (обычно 01.01.1970). Разница между двумя вызовами — затраченное время.import time
start = time.time()
result = sum(range(10_000_000))
end = time.time()
print(f"Result: {result}")
print(f"Elapsed: {end - start:.4f} seconds")
Но у этого подхода есть минус: точность зависит от системных часов, которые могут “прыгать”.
---
## Более точный замер:
time.perf_counterДля профилирования (измерения скорости) лучше использовать
perf_counter(). Это монотонный счётчик: не зависит от системного времени и даёт максимальную доступную точность.import time
start = time.perf_counter()
data = [x ** 2 for x in range(1_000_000)]
end = time.perf_counter()
print(f"Elapsed: {end - start:.6f} seconds")
Используйте
perf_counter везде, где важна точность измерений, особенно в тестах производительности.---
## Имитируем “медленный” внешний сервис
Представьте, что вы пишете функцию, которая обращается к API, но настоящего API ещё нет. Можно сделать фейковую задержку:
import time
import random
def fake_api_call():
delay = random.uniform(0.5, 1.5)
time.sleep(delay)
return {"status": "ok", "delay": delay}
start = time.perf_counter()
response = fake_api_call()
end = time.perf_counter()
print(response)
print(f"Real elapsed: {end - start:.3f} seconds")
Так удобно тестировать:
- обработку долгих ответов,
- таймауты,
- индикаторы загрузки.
---
## Мини-профайлер на коленке
Можно написать простый декоратор для измерения времени выполнения любой функции.
import time
from functools import wraps
def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} took {end - start:.5f} seconds")
return result
return wrapper
@timeit
def slow_function():
time.sleep(1)
return "done"
slow_function()
Так вы быстро находите “узкие места” без тяжёлых инструментов.
---
Модуль
time кажется простым, но это мощный инструмент: с ним вы можете и измерять производительность, и контролировать темп выполнения программы. А это уже шаг от “просто работает” к “работает предсказуемо и управляемо”.👍3❤1🔥1🤩1