Преобразование текста в речь с помощью pyttsx3: заставляем Python говорить
Иногда куда удобнее услышать результат работы программы, чем читать его в консоли. Например, при создании голосового помощника, озвучивании уведомлений или чтении текстов вслух. Для этого в Python есть отличный модуль —
---
## Установка
---
## Первый голос программы
Минимальный пример:
Разбор по шагам:
-
-
-
---
## Управление скоростью и громкостью
Сделаем речь быстрее и тише:
Полезно, если вы хотите, чтобы уведомления говорились короче и быстрее, а чтение длинных текстов — медленнее и отчётливее.
---
## Выбор голоса
На системе может быть несколько голосов (мужской, женский, разные языки). Посмотрим, что доступно:
Выбор голоса по индексу:
Если у вас установлены дополнительные русские/английские голоса, их можно выбрать по
---
## Сохранение речи в аудиофайл
Озвучку можно не только проигрывать сразу, но и сохранять в файл, например, чтобы сделать аудиоверсию текста:
Теперь
---
Иногда куда удобнее услышать результат работы программы, чем читать его в консоли. Например, при создании голосового помощника, озвучивании уведомлений или чтении текстов вслух. Для этого в Python есть отличный модуль —
pyttsx3.pyttsx3 — офлайн‑движок синтеза речи: интернет не нужен, библиотека использует системные голосовые движки (SAPI5 на Windows, NSSpeechSynthesizer на macOS, eSpeak на Linux).---
## Установка
pip install pyttsx3
---
## Первый голос программы
Минимальный пример:
import pyttsx3
engine = pyttsx3.init()
engine.say("Hello, Python world!")
engine.runAndWait()
Разбор по шагам:
-
init() создаёт объект движка;-
say() добавляет текст в очередь;-
runAndWait() запускает озвучку и ждёт её завершения.---
## Управление скоростью и громкостью
Сделаем речь быстрее и тише:
import pyttsx3
engine = pyttsx3.init()
rate = engine.getProperty("rate")
volume = engine.getProperty("volume")
engine.setProperty("rate", rate + 50) # быстрее
engine.setProperty("volume", volume - 0.2) # тише (0.0–1.0)
engine.say("This is a faster and quieter voice.")
engine.runAndWait()
Полезно, если вы хотите, чтобы уведомления говорились короче и быстрее, а чтение длинных текстов — медленнее и отчётливее.
---
## Выбор голоса
На системе может быть несколько голосов (мужской, женский, разные языки). Посмотрим, что доступно:
import pyttsx3
engine = pyttsx3.init()
voices = engine.getProperty("voices")
for idx, voice in enumerate(voices):
print(idx, voice.id)
Выбор голоса по индексу:
engine.setProperty("voice", voices[0].id)
engine.say("Using the first available voice.")
engine.runAndWait()
Если у вас установлены дополнительные русские/английские голоса, их можно выбрать по
voice.id, проверяя в выводе нужный язык.---
## Сохранение речи в аудиофайл
Озвучку можно не только проигрывать сразу, но и сохранять в файл, например, чтобы сделать аудиоверсию текста:
import pyttsx3
engine = pyttsx3.init()
engine.save_to_file("This text will be saved to an audio file.", "output.mp3")
engine.runAndWait()
Теперь
output.mp3 можно отправить, встроить в приложение или проиграть через любой плеер.---
pyttsx3 — отличный старт для тех, кто хочет добавить в свои программы голос: от простых напоминаний до прототипов ассистентов и читалок. Попробуйте озвучить результаты своих скриптов — Python начнёт разговаривать с вами буквально.❤4
Отправка писем через SMTP с модулем
Представь: твой скрипт сам отправляет отчёт на почту каждое утро. Без ручного вмешательства, без «сейчас напишу письмо». В Python это делается в несколько строк с помощью модуля
## Базовая отправка письма
Простейший пример: отправим текстовое письмо через SMTP-сервер (например, Gmail):
Ключевые моменты:
-
-
-
Важно: многие почтовые сервисы требуют «пароль приложения», а не обычный пароль аккаунта.
## Форматирование письма по-взрослому
Реальные письма состоят из заголовков и тела, часто в нескольких форматах (текст + HTML). Удобнее собирать их через
Здесь
## Мини-чеклист по безопасности
- Не храни пароль в коде — используй переменные окружения или
- Всегда используй
- Тестируй сначала на своём ящике, а не на почте начальника.
Умение отправлять письма из скрипта открывает массу возможностей: автоматические отчёты, уведомления о падении сервиса, напоминания о дедлайнах — всё это можно делегировать Python.
smtplibПредставь: твой скрипт сам отправляет отчёт на почту каждое утро. Без ручного вмешательства, без «сейчас напишу письмо». В Python это делается в несколько строк с помощью модуля
smtplib.## Базовая отправка письма
SMTP — это протокол для отправки почты. В Python за него отвечает стандартный модуль smtplib, ничего ставить не нужно.Простейший пример: отправим текстовое письмо через SMTP-сервер (например, Gmail):
import smtplib
smtp_server = "smtp.gmail.com"
smtp_port = 587
sender_email = "you@example.com"
password = "your_app_password"
receiver_email = "friend@example.com"
message = """\
From: you@example.com
To: friend@example.com
Subject: Test email from Python
Hello! This is a test email sent via smtplib.
"""
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls() # шифруем соединение
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
Ключевые моменты:
-
starttls() — включает шифрование (TLS).-
login() — авторизация на почтовом сервере.-
sendmail() — отправка письма (от кого, кому, текст письма целиком).Важно: многие почтовые сервисы требуют «пароль приложения», а не обычный пароль аккаунта.
## Форматирование письма по-взрослому
Реальные письма состоят из заголовков и тела, часто в нескольких форматах (текст + HTML). Удобнее собирать их через
email-модуль.import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
smtp_server = "smtp.gmail.com"
smtp_port = 587
sender_email = "you@example.com"
password = "your_app_password"
receiver_email = "friend@example.com"
msg = MIMEMultipart("alternative")
msg["Subject"] = "Report from Python script"
msg["From"] = sender_email
msg["To"] = receiver_email
text_part = """\
Hi!
Here is your daily report in plain text.
"""
html_part = """\
<html>
<body>
<h2>Daily report</h2>
<p>This is a <b>HTML</b> version of the email.</p>
</body>
</html>
"""
msg.attach(MIMEText(text_part, "plain"))
msg.attach(MIMEText(html_part, "html"))
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(sender_email, password)
server.send_message(msg)
Здесь
send_message() принимает уже готовый объект письма, а не строку.## Мини-чеклист по безопасности
- Не храни пароль в коде — используй переменные окружения или
.env.- Всегда используй
starttls() или SMTP_SSL.- Тестируй сначала на своём ящике, а не на почте начальника.
Умение отправлять письма из скрипта открывает массу возможностей: автоматические отчёты, уведомления о падении сервиса, напоминания о дедлайнах — всё это можно делегировать Python.
👍4❤1🔥1
Парсинг аргументов командной строки:
---------------------------------------------------------------
Когда вы запускаете скрипт так:
Python передаёт все эти штуки после
###
Плюсы
- минимум магии, обычный список;
- полезен для одноразовых скриптов в несколько строк.
Минусы:
- сами пишете помощь (
- сами валидируете типы и диапазоны;
- сами обрабатываете ошибки и необязательные флаги.
Как только аргументов становится больше трёх — код превращается в лапшу с
###
Что делает
- автоматически создаёт
- преобразует типы (
- проверяет обязательные аргументы (
- поддерживает флаги (
- умеет подкоманды (
Пример запуска:
### Когда что выбирать
- Скрипт на 5–10 строк, пара позиционных аргументов, вы один раз запустите и забудете — можно использовать
- Всё, что будет жить дольше одного дня, запускаться другими людьми или иметь больше пары опций — берите
Цена входа минимальна, а взамен вы получаете автодокументацию, валидацию и гораздо более читаемый код.
По сути,
argparse против sys.argv---------------------------------------------------------------
Когда вы запускаете скрипт так:
python app.py --name Alice --count 3
Python передаёт все эти штуки после
app.py в ваш код. Есть два популярных способа это разобрать: голый массив sys.argv и модуль argparse. Они решают одну задачу, но ощущения от работы — как от велосипеда без тормозов и современного велосипеда с гидравликой.###
sys.argv: минимализм и ручная работаsys.argv — это просто список строк: первый элемент — имя файла, дальше — аргументы.import sys
def main():
args = sys.argv[1:] # пропускаем имя скрипта
if len(args) != 2:
print("Usage: python app.py <name> <count>")
sys.exit(1)
name = args[0]
try:
count = int(args[1])
except ValueError:
print("count must be integer")
sys.exit(1)
for _ in range(count):
print(f"Hello, {name}!")
if __name__ == "__main__":
main()
Плюсы
sys.argv:- минимум магии, обычный список;
- полезен для одноразовых скриптов в несколько строк.
Минусы:
- сами пишете помощь (
Usage: ...);- сами валидируете типы и диапазоны;
- сами обрабатываете ошибки и необязательные флаги.
Как только аргументов становится больше трёх — код превращается в лапшу с
if и try/except.###
argparse: встроенный “CLI-конструктор”argparse делает почти всё это за вас.import argparse
def build_parser():
parser = argparse.ArgumentParser(
description="Simple greeting script"
)
parser.add_argument(
"--name",
required=True,
help="Name to greet"
)
parser.add_argument(
"--count",
type=int,
default=1,
help="How many times to greet"
)
parser.add_argument(
"--loud",
action="store_true",
help="Use upper case for greeting"
)
return parser
def main():
parser = build_parser()
args = parser.parse_args()
message = f"Hello, {args.name}!"
if args.loud:
message = message.upper()
for _ in range(args.count):
print(message)
if __name__ == "__main__":
main()
Что делает
argparse:- автоматически создаёт
--help и аккуратный текст помощи;- преобразует типы (
type=int, float, pathlib.Path, свои функции);- проверяет обязательные аргументы (
required=True);- поддерживает флаги (
action="store_true");- умеет подкоманды (
git commit, git push-стайл).Пример запуска:
python app.py --help
python app.py --name Bob --count 3 --loud
### Когда что выбирать
- Скрипт на 5–10 строк, пара позиционных аргументов, вы один раз запустите и забудете — можно использовать
sys.argv.- Всё, что будет жить дольше одного дня, запускаться другими людьми или иметь больше пары опций — берите
argparse. Цена входа минимальна, а взамен вы получаете автодокументацию, валидацию и гораздо более читаемый код.
По сути,
sys.argv — это сырые данные, а argparse — готовый интерфейс командной строки. Начать стоит уметь с обоими, но писать серьёзные утилиты на “голом” sys.argv — как собирать шкаф без отвертки: возможно, но слишком больно.👍2🔥1
Создание тестов с pytest: простая проверка вашего кода
Если вы пишете код без тестов — вы просто верите, что он работает.
### Почему именно pytest
Минимальный порог входа: достаточно обычных `assert`.
Никаких классических «классов тестов» как в
Красивый вывод ошибок.
Работает и с маленькими скриптами, и с крупными проектами.
Установим:
### Первый тест за 2 минуты
Пусть есть файл
Создадим файл
Запуск в терминале:
### Что делает pytest удобным
1. Человеческие assert’ы
Никаких
Если тест упадет, вы получите наглядный дифф значений.
2. Параметризованные тесты
Одна функция теста — несколько наборов данных:
Так вы быстро покрываете типичные случаи и крайние значения.
3. Проверка исключений
Многие ошибки — это не только «плохой результат», но и «правильное исключение».
### Как встроить pytest в свою работу
1. Создавайте для каждого файла
2. Добавляйте тест при каждом исправлении бага: сначала тест, который падает, потом фикс.
3. Регулярно запускайте:
---
Если вы пишете код без тестов — вы просто верите, что он работает.
pytest позволяет вместо веры получить факты: быстро, просто и без боли.### Почему именно pytest
Минимальный порог входа: достаточно обычных `assert`.
Никаких классических «классов тестов» как в
unittest.Красивый вывод ошибок.
Работает и с маленькими скриптами, и с крупными проектами.
Установим:
pip install pytest
### Первый тест за 2 минуты
Пусть есть файл
math_utils.py:# math_utils.py
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("b must not be zero")
return a / b
Создадим файл
test_math_utils.py:# test_math_utils.py
from math_utils import add, divide
def test_add_two_positive_numbers():
assert add(2, 3) == 5
def test_add_with_negative_number():
assert add(-1, 4) == 3
def test_divide_normal_case():
assert divide(10, 2) == 5
def test_divide_by_zero_raises():
import pytest
with pytest.raises(ValueError):
divide(10, 0)
Запуск в терминале:
pytest
pytest сам найдет все файлы вида test_*.py и функции test_*.### Что делает pytest удобным
1. Человеческие assert’ы
Никаких
self.assertEqual(...). Пишем:def test_substring():
text = "hello world"
assert "world" in text
Если тест упадет, вы получите наглядный дифф значений.
2. Параметризованные тесты
Одна функция теста — несколько наборов данных:
import pytest
from math_utils import add
@pytest.mark.parametrize(
"a, b, expected",
[
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
]
)
def test_add_parametrized(a, b, expected):
assert add(a, b) == expected
Так вы быстро покрываете типичные случаи и крайние значения.
3. Проверка исключений
Многие ошибки — это не только «плохой результат», но и «правильное исключение».
pytest.raises делает такой тест читабельным, как в примере с divide.### Как встроить pytest в свою работу
1. Создавайте для каждого файла
xxx.py файл test_xxx.py.2. Добавляйте тест при каждом исправлении бага: сначала тест, который падает, потом фикс.
3. Регулярно запускайте:
pytest -q
-q делает вывод короче и приятнее.---
pytest — это привычка, которая экономит часы отладки. Стоит один раз настроить минимальный набор тестов — и ваш Python-код перестает быть «черной коробкой» и начинает честно рассказывать, где он ломается.❤2
Как работать с очередями заданий с библиотекой
Представьте, что у вас есть список задач, которые нужно выполнить: скачать файлы, обработать данные, отправить письма. Если делать всё по очереди в одном потоке — программа “тупо” ждёт завершения каждой операции. Очереди заданий позволяют распределить работу между несколькими потоками и не потерять ни одной задачи.
В Python для этого есть модуль
---
### Базовый пример: очередь задач
Методы:
-
-
-
-
---
### Очередь + потоки: простой пул воркеров
Типичный сценарий: один поток генерирует задачи, несколько потоков их обрабатывают.
Ключевой момент: очередь сама заботится о синхронизации между потоками — вам не нужны явные блокировки.
---
### Другие типы очередей
-
-
Пример приоритетной очереди: задачи с меньшим числом выполняются раньше.
---
queueПредставьте, что у вас есть список задач, которые нужно выполнить: скачать файлы, обработать данные, отправить письма. Если делать всё по очереди в одном потоке — программа “тупо” ждёт завершения каждой операции. Очереди заданий позволяют распределить работу между несколькими потоками и не потерять ни одной задачи.
В Python для этого есть модуль
queue, который обеспечивает потокобезопасную очередь.---
### Базовый пример: очередь задач
import queue
task_queue = queue.Queue()
# добавляем задачи
task_queue.put("download_file_1")
task_queue.put("download_file_2")
task_queue.put("process_data")
while not task_queue.empty():
task = task_queue.get()
print("Handling:", task)
task_queue.task_done()
Queue() по умолчанию — неограниченная по размеру. Методы:
-
put(item) — добавить задачу-
get() — взять задачу (если очереди пустая — ждёт)-
task_done() — сообщить, что задача обработана-
join() — подождать, пока все задачи будут помечены как выполненные---
### Очередь + потоки: простой пул воркеров
Типичный сценарий: один поток генерирует задачи, несколько потоков их обрабатывают.
import queue
import threading
import time
task_queue = queue.Queue()
def worker(worker_id):
while True:
task = task_queue.get()
if task is None: # сигнал остановки
task_queue.task_done()
break
print(f"Worker {worker_id} handling {task}")
time.sleep(0.5) # имитация работы
task_queue.task_done()
# запускаем 3 обработчика
workers = []
for i in range(3):
t = threading.Thread(target=worker, args=(i,))
t.start()
workers.append(t)
# добавляем задачи
for n in range(10):
task_queue.put(f"task_{n}")
# ждём завершения всех задач
task_queue.join()
# останавливаем воркеров
for _ in workers:
task_queue.put(None)
for t in workers:
t.join()
Ключевой момент: очередь сама заботится о синхронизации между потоками — вам не нужны явные блокировки.
---
### Другие типы очередей
queue предлагает не только обычную FIFO-очередь:-
queue.LifoQueue — стек (последний вошёл — первый вышел)-
queue.PriorityQueue — приоритетная очередьПример приоритетной очереди: задачи с меньшим числом выполняются раньше.
import queue
pq = queue.PriorityQueue()
pq.put((1, "low_priority"))
pq.put((0, "high_priority"))
pq.put((5, "very_low_priority"))
while not pq.empty():
priority, task = pq.get()
print(priority, task)
pq.task_done()
---
queue — это простой способ построить систему обработки заданий: от игрушечного пула потоков до мини-очереди задач внутри вашей программы. Понимание этих примитивов — отличный шаг к написанию более масштабных и отзывчивых приложений на Python.👍3🔥1
Сортировка и фильтрация словарей по значениям и ключам
Словарь в Python — отличный способ хранить данные вида «ключ → значение». Но реальная магия начинается, когда нужно отсортировать или отфильтровать этот хаос. Разберёмся, как это делать красиво и понятно.
---
### Сортировка словаря по ключам и значениям
У нас есть словарь с результатами теста:
Сортировка по ключам (по имени):
Сортировка по значениям (по баллам):
Чтобы отсортировать по убыванию:
---
### Сортировка с дополнительным критерием
Представьте, что нужно отсортировать по баллам по убыванию, а при равных баллах — по имени по возрастанию.
Мы используем кортеж в качестве ключа сортировки: сначала минус баллы (для убывания), потом имя.
---
### Фильтрация словаря
Допустим, нам нужны только те, у кого больше 80 баллов.
Это dict comprehension — мощный и читаемый способ фильтрации.
Можно фильтровать и по ключам:
---
### Комбинируем: фильтрация + сортировка
Например: взять только тех, у кого баллы > 80, и отсортировать по имени.
Или вообще без промежуточной переменной:
---
Умение сортировать и фильтровать словари — один из тех навыков, который сразу делает код аккуратнее и понятнее. А дальше можно подключать
Словарь в Python — отличный способ хранить данные вида «ключ → значение». Но реальная магия начинается, когда нужно отсортировать или отфильтровать этот хаос. Разберёмся, как это делать красиво и понятно.
---
### Сортировка словаря по ключам и значениям
У нас есть словарь с результатами теста:
scores = {
"alice": 85,
"bob": 92,
"charlie": 78,
"david": 92
}
Сортировка по ключам (по имени):
sorted_by_name = dict(sorted(scores.items(), key=lambda item: item[0]))
print(sorted_by_name)
# {'alice': 85, 'bob': 92, 'charlie': 78, 'david': 92}
item[0] — это ключ (имя). sorted() возвращает список пар (key, value), а dict(...) снова собирает словарь.Сортировка по значениям (по баллам):
sorted_by_score = dict(sorted(scores.items(), key=lambda item: item[1]))
print(sorted_by_score)
# {'charlie': 78, 'alice': 85, 'bob': 92, 'david': 92}
item[1] — значение (баллы). Чтобы отсортировать по убыванию:
sorted_by_score_desc = dict(sorted(scores.items(), key=lambda item: item[1], reverse=True))
---
### Сортировка с дополнительным критерием
Представьте, что нужно отсортировать по баллам по убыванию, а при равных баллах — по имени по возрастанию.
sorted_complex = dict(sorted(
scores.items(),
key=lambda item: (-item[1], item[0])
))
print(sorted_complex)
# {'bob': 92, 'david': 92, 'alice': 85, 'charlie': 78}
Мы используем кортеж в качестве ключа сортировки: сначала минус баллы (для убывания), потом имя.
---
### Фильтрация словаря
Допустим, нам нужны только те, у кого больше 80 баллов.
filtered_scores = {
name: score
for name, score in scores.items()
if score > 80
}
print(filtered_scores)
# {'alice': 85, 'bob': 92, 'david': 92}
Это dict comprehension — мощный и читаемый способ фильтрации.
Можно фильтровать и по ключам:
filtered_by_name = {
name: score
for name, score in scores.items()
if name.startswith("a")
}
print(filtered_by_name)
# {'alice': 85}
---
### Комбинируем: фильтрация + сортировка
Например: взять только тех, у кого баллы > 80, и отсортировать по имени.
filtered = {
name: score
for name, score in scores.items()
if score > 80
}
result = dict(sorted(filtered.items(), key=lambda item: item[0]))
print(result)
# {'alice': 85, 'bob': 92, 'david': 92}
Или вообще без промежуточной переменной:
result = dict(sorted(
(
(name, score)
for name, score in scores.items()
if score > 80
),
key=lambda item: item[0]
))
---
Умение сортировать и фильтровать словари — один из тех навыков, который сразу делает код аккуратнее и понятнее. А дальше можно подключать
operator.itemgetter, functools.partial и другие инструменты, но фундамент вы уже видите: sorted(), lambda, и comprehension — ваше основное оружие.🔥4
Как выполнять задачи по расписанию с помощью
Иногда нужно, чтобы скрипт сам что‑то делал: раз в минуту проверял почту, каждый день делал бэкап или раз в час напоминал «пора сделать перерыв». Писать собственный планировщик — лишняя боль, когда есть простой модуль
---
### Установка
---
### Базовая идея
1. Определяем задачу — обычную функцию.
2. Назначаем ей расписание.
3. Запускаем бесконечный цикл, который проверяет, не пора ли что‑то выполнить.
Простейший пример:
Здесь
---
### Расписание посерьёзнее
Формат времени — строка
---
### Передача аргументов в задачи
Функция‑задача может принимать аргументы:
---
### Управление задачами
Иногда нужно отменить часть расписания:
---
### Когда использовать
- простых фоновых задач;
- учебных проектов и прототипов;
- скриптов, которые всегда крутятся на одном сервере/ПК.
Для сложных продакшн‑систем чаще берут
scheduleИногда нужно, чтобы скрипт сам что‑то делал: раз в минуту проверял почту, каждый день делал бэкап или раз в час напоминал «пора сделать перерыв». Писать собственный планировщик — лишняя боль, когда есть простой модуль
schedule.---
### Установка
pip install schedule
---
### Базовая идея
schedule работает по принципу:1. Определяем задачу — обычную функцию.
2. Назначаем ей расписание.
3. Запускаем бесконечный цикл, который проверяет, не пора ли что‑то выполнить.
Простейший пример:
import schedule
import time
def send_report():
print("Sending report...")
schedule.every(10).seconds.do(send_report)
while True:
schedule.run_pending()
time.sleep(1)
Здесь
send_report() запускается каждые 10 секунд. run_pending() проверяет «наступило ли время» для задач, а sleep(1) просто не даёт циклу крутиться без паузы.---
### Расписание посерьёзнее
schedule умеет работать с минутами, часами, днями и даже днями недели:import schedule
import time
def backup_db():
print("Backup created")
def remind_break():
print("Time to take a break!")
schedule.every().day.at("23:30").do(backup_db) # каждый день в 23:30
schedule.every(15).minutes.do(remind_break) # каждые 15 минут
schedule.every().monday.at("09:00").do(backup_db) # каждый понедельник в 09:00
while True:
schedule.run_pending()
time.sleep(1)
Формат времени — строка
"HH:MM" в 24‑часовом формате.---
### Передача аргументов в задачи
Функция‑задача может принимать аргументы:
import schedule
import time
def send_email(to, subject):
print(f"Email to {to}: {subject}")
schedule.every().hour.do(send_email, to="admin@example.com",
subject="Hourly status")
while True:
schedule.run_pending()
time.sleep(1)
---
### Управление задачами
Иногда нужно отменить часть расписания:
import schedule
def clear_cache():
print("Cache cleared")
job = schedule.every().hour.do(clear_cache)
# Удалить конкретную задачу
schedule.cancel_job(job)
# Удалить все задачи
schedule.clear()
---
### Когда использовать
scheduleschedule отлично подходит для:- простых фоновых задач;
- учебных проектов и прототипов;
- скриптов, которые всегда крутятся на одном сервере/ПК.
Для сложных продакшн‑систем чаще берут
cron, Celery и подобные инструменты, но для начала schedule даёт очень удобный и наглядный вход в мир планировщиков задач.👍3
Создание простого API‑клиента с
Рано или поздно каждый питонист сталкивается с задачей: “Нужно что‑то забрать из интернета… программно”. Тут на сцену выходит связка
---
### Что такое API и зачем нам клиент?
API — это “договор” о том, как общаться с сервисом: по какому адресу стучаться, какие параметры передавать, в каком формате будет ответ.
Чаще всего ответ приходит в формате JSON — структуре, очень похожей на словари и списки Python.
Наша задача:
1. Отправить HTTP‑запрос (
2. Получить ответ.
3. Превратить JSON в привычные объекты Python.
---
### Первый запрос: получаем данные
Установим библиотеку:
Простейший клиент:
Но текст — это неудобно. Лучше сразу разобрать JSON:
---
### Параметры запроса и мини‑клиент
Обычно API принимает параметры. Например, выбираем несколько постов:
Здесь важно:
-
-
---
### Отправка данных:
Иногда нужно не только читать, но и отправлять информацию:
Флаг
- автоматически превращает словарь в JSON;
- выставляет заголовок
---
### На что обратить внимание дальше
- Тайм-ауты:
- Заголовки:
- Логику удобно оборачивать в класс
Этой базой уже можно за вечер прикрутить свой скрипт к реальному веб‑сервису: от погоды до телеграм‑ботов — везде вокруг API, а
requests и jsonРано или поздно каждый питонист сталкивается с задачей: “Нужно что‑то забрать из интернета… программно”. Тут на сцену выходит связка
requests + json — минимальный набор, чтобы подружиться с любым более‑менее современным веб‑сервером.---
### Что такое API и зачем нам клиент?
API — это “договор” о том, как общаться с сервисом: по какому адресу стучаться, какие параметры передавать, в каком формате будет ответ.
Чаще всего ответ приходит в формате JSON — структуре, очень похожей на словари и списки Python.
Наша задача:
1. Отправить HTTP‑запрос (
GET, POST, …). 2. Получить ответ.
3. Превратить JSON в привычные объекты Python.
---
### Первый запрос: получаем данные
Установим библиотеку:
pip install requests
Простейший клиент:
import requests
url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)
print(response.status_code) # 200?
print(response.text[:100]) # сырой текст ответа
Но текст — это неудобно. Лучше сразу разобрать JSON:
import json
import requests
url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)
if response.status_code == 200:
data = json.loads(response.text)
# эквивалентно: data = response.json()
print(type(data)) # <class 'dict'>
print(data["title"]) # доступ к полям, как в обычном словаре
else:
print("Request failed:", response.status_code)
---
### Параметры запроса и мини‑клиент
Обычно API принимает параметры. Например, выбираем несколько постов:
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def get_posts(limit=5):
params = {"_limit": limit}
response = requests.get(f"{BASE_URL}/posts", params=params)
response.raise_for_status() # выбросит исключение при ошибке
return response.json()
posts = get_posts(limit=3)
for post in posts:
print(f"{post['id']}: {post['title']}")
Здесь важно:
-
params — словарь, который requests превращает в query‑строку (?key=value).-
response.raise_for_status() — простой способ не забыть про обработку ошибок.---
### Отправка данных:
POST с JSONИногда нужно не только читать, но и отправлять информацию:
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def create_post(title, body, user_id=1):
payload = {
"title": title,
"body": body,
"userId": user_id,
}
response = requests.post(f"{BASE_URL}/posts", json=payload)
response.raise_for_status()
return response.json()
new_post = create_post("Hello API", "This is my first API client!")
print(new_post)
Флаг
json=payload:- автоматически превращает словарь в JSON;
- выставляет заголовок
Content-Type: application/json.---
### На что обратить внимание дальше
- Тайм-ауты:
requests.get(url, timeout=5) - Заголовки:
headers={"Authorization": "Bearer <token>"} - Логику удобно оборачивать в класс
ApiClient, если эндпоинтов много.Этой базой уже можно за вечер прикрутить свой скрипт к реальному веб‑сервису: от погоды до телеграм‑ботов — везде вокруг API, а
requests + json превращают их в обычные словари и списки Python.👍2
Как распарсить текстовое меню и извлечь информацию
Иногда нам достается меню не в виде аккуратного JSON, а просто куском текста: письмо от администратора, скопированное меню из чата или лог старой системы. Но даже из такого «хаоса» можно вытащить структурированные данные с помощью Python.
Представим, что у нас есть такое меню:
Наша цель — превратить это в список словарей:
### Вариант 1: Базовый парсинг со split
Для очень простых и предсказуемых форматов можно обойтись без регулярных выражений:
Результат:
Такой подход хорош, когда формат жёстко фиксирован и вы его контролируете.
### Вариант 2: Регулярные выражения для «живого» текста
Если в меню могут быть пробелы, произвольные номера позиций или даже валюта, лучше использовать
### Вариант 3: Превращаем парсер в функцию
Хорошая практика — оборачивать логику парсинга в функцию: потом вы сможете менять реализацию, не трогая остальной код.
Дальше с этим списком уже можно делать всё что угодно: считать среднюю цену, фильтровать по бюджету, строить API или генератор PDF-меню.
Парсинг текстовых меню — отличный тренировочный полигон: вы прокачиваете строки, регулярные выражения, функции и немного алгоритмическое мышление. А заодно перестаёте бояться «грязных» данных: Python умеет наводить порядок.
Иногда нам достается меню не в виде аккуратного JSON, а просто куском текста: письмо от администратора, скопированное меню из чата или лог старой системы. Но даже из такого «хаоса» можно вытащить структурированные данные с помощью Python.
Представим, что у нас есть такое меню:
1. Margherita - 350
2. Pepperoni - 420
3. Four Cheese - 500
4. Vegan Special - 390
Наша цель — превратить это в список словарей:
{"name": ..., "price": ...}.### Вариант 1: Базовый парсинг со split
Для очень простых и предсказуемых форматов можно обойтись без регулярных выражений:
menu_text = """
1. Margherita - 350
2. Pepperoni - 420
3. Four Cheese - 500
4. Vegan Special - 390
"""
items = []
for line in menu_text.strip().splitlines():
if not line.strip():
continue
# "1. Margherita - 350" -> ["1. Margherita ", " 350"]
left, price_str = line.split('-')
price = int(price_str.strip())
# "1. Margherita " -> ["1.", "Margherita"]
_, name = left.split('.', maxsplit=1)
items.append({
"name": name.strip(),
"price": price
})
print(items)
Результат:
[
{'name': 'Margherita', 'price': 350},
{'name': 'Pepperoni', 'price': 420},
...
]
Такой подход хорош, когда формат жёстко фиксирован и вы его контролируете.
### Вариант 2: Регулярные выражения для «живого» текста
Если в меню могут быть пробелы, произвольные номера позиций или даже валюта, лучше использовать
re:import re
menu_text = """
1) Margherita - 350 RUB
02. Pepperoni — 420
#3 Four Cheese: 500р
4 Vegan Special 390
"""
pattern = re.compile(
r"""
^\D*?(\d+)\D+ # номер блюда
([A-Za-z ]+?)\D+ # название
(\d+)\s* # цена
""",
re.VERBOSE
)
items = []
for line in menu_text.strip().splitlines():
match = pattern.search(line)
if not match:
continue
pos, name, price = match.groups()
items.append({
"position": int(pos),
"name": name.strip(),
"price": int(price)
})
print(items)
re.VERBOSE позволяет красиво документировать шаблон и не превращать его в нечитаемое «простыню» из символов.### Вариант 3: Превращаем парсер в функцию
Хорошая практика — оборачивать логику парсинга в функцию: потом вы сможете менять реализацию, не трогая остальной код.
def parse_menu(text: str):
import re
pattern = re.compile(r'^\s*\d+\D+([A-Za-z ]+)\D+(\d+)', re.MULTILINE)
result = []
for name, price in pattern.findall(text):
result.append({
"name": name.strip(),
"price": int(price)
})
return result
menu_items = parse_menu(menu_text)
Дальше с этим списком уже можно делать всё что угодно: считать среднюю цену, фильтровать по бюджету, строить API или генератор PDF-меню.
Парсинг текстовых меню — отличный тренировочный полигон: вы прокачиваете строки, регулярные выражения, функции и немного алгоритмическое мышление. А заодно перестаёте бояться «грязных» данных: Python умеет наводить порядок.
👍1
Использование модификаторов доступа в классах: public, private, protected
В Python нет классических модификаторов доступа как в Java или C++ — никаких
---
## Public: по умолчанию открыто
Все атрибуты без подчеркиваний считаются публичными.
Публичные атрибуты — часть интерфейса класса. Менять их снаружи — нормально (если это предусмотрено логикой).
---
## Protected: одно подчеркивание
Одно подчеркивание — это сигнал разработчикам: "не трогайте это снаружи без необходимости". Это не защита, а соглашение.
Чаще всего такие атрибуты используются для наследования: дочерний класс может работать с
---
## Private: двойное подчеркивание и name mangling
Двойное подчеркивание включает механизм name mangling: имя переписывается в
Использовать
- хотите защититься от случайного переопределения в наследниках;
- явно обозначаете: "это строго внутренняя деталь реализации".
---
## Как выбирать?
- Публичное (
- Protected (
- Private (
Главное: в Python модификаторы — это не про «запрет», а про договор между разработчиками. Уважайте подчеркивания — и ваш код станет чище и понятнее.
В Python нет классических модификаторов доступа как в Java или C++ — никаких
public, private и protected в синтаксисе. Но есть соглашения и немного магии с подчеркиваниями, которые позволяют удобно управлять доступом к данным внутри класса.---
## Public: по умолчанию открыто
Все атрибуты без подчеркиваний считаются публичными.
class User:
def __init__(self, name):
self.name = name # public
def greet(self):
return f"Hello, {self.name}!"
u = User("Alice")
print(u.name) # OK
print(u.greet()) # OK
Публичные атрибуты — часть интерфейса класса. Менять их снаружи — нормально (если это предусмотрено логикой).
---
## Protected: одно подчеркивание
Одно подчеркивание — это сигнал разработчикам: "не трогайте это снаружи без необходимости". Это не защита, а соглашение.
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # public
self._balance = balance # protected (по соглашению)
def deposit(self, amount):
self._balance += amount
def get_balance(self):
return self._balance
acc = BankAccount("Bob", 100)
acc.deposit(50)
print(acc.get_balance()) # 150
# Технически можно, но «не по правилам»:
acc._balance = 1_000_000
Чаще всего такие атрибуты используются для наследования: дочерний класс может работать с
_balance, но внешний код — по идее нет.---
## Private: двойное подчеркивание и name mangling
Двойное подчеркивание включает механизм name mangling: имя переписывается в
_ИмяКласса__атрибут. Это защищает от случайного доступа и конфликтов в наследовании.class SecureAccount:
def __init__(self, pin):
self.__pin = pin # private
def check_pin(self, pin):
return pin == self.__pin
sa = SecureAccount("1234")
print(sa.check_pin("0000")) # False
# Прямой доступ не сработает:
# print(sa.__pin) # AttributeError
# Но Python не ставит абсолютных стен:
print(sa._SecureAccount__pin) # "1234"
Использовать
__name стоит, когда вы:- хотите защититься от случайного переопределения в наследниках;
- явно обозначаете: "это строго внутренняя деталь реализации".
---
## Как выбирать?
- Публичное (
name): часть API, с этим могут работать все.- Protected (
_name): внутренняя деталь, можно трогать лишь в крайних случаях и обычно внутри иерархии классов.- Private (
__name): скрытая реализация, которую вы не планируете трогать извне и в наследниках.Главное: в Python модификаторы — это не про «запрет», а про договор между разработчиками. Уважайте подчеркивания — и ваш код станет чище и понятнее.
❤2🔥2