Создаём свой первый CLI-инструмент с argparse
Рано или поздно каждый питонист приходит к мысли: «Хочу свою консольную утилиту!» Что‑нибудь, что запускается из терминала, принимает аргументы и делает полезное дело. В Python для этого есть отличный модуль
---
### Зачем вообще нужны аргументы?
Без аргументов ваш скрипт живёт в режиме «одна команда — один результат». А с аргументами можно:
- менять режим работы (
- передавать файлы (
- переключать формат вывода (
И всё это без изменения кода — просто другими параметрами запуска.
---
### Базовый пример: мини-калькулятор
Создадим файл
Теперь можно запускать:
- показывать
- проверять типы (
- ограничивать значения (
- задавать значения по умолчанию (
---
### Пара фишек, которые часто забывают
1. Флаг без значения — просто наличие/отсутствие:
Теперь
2. Переиспользование логики
Лучше выносить «деловую» логику в отдельные функции — тогда скрипт проще тестировать и расширять:
---
CLI-инструмент в Python — это буквально несколько строк с
Рано или поздно каждый питонист приходит к мысли: «Хочу свою консольную утилиту!» Что‑нибудь, что запускается из терминала, принимает аргументы и делает полезное дело. В Python для этого есть отличный модуль
argparse.---
### Зачем вообще нужны аргументы?
Без аргументов ваш скрипт живёт в режиме «одна команда — один результат». А с аргументами можно:
- менять режим работы (
--verbose, --quiet)- передавать файлы (
--input file.txt)- переключать формат вывода (
--json, --text)И всё это без изменения кода — просто другими параметрами запуска.
---
### Базовый пример: мини-калькулятор
Создадим файл
calc.py, который принимает два числа и операцию:import argparse
def main():
parser = argparse.ArgumentParser(
description="Simple CLI calculator"
)
parser.add_argument("a", type=float, help="First number")
parser.add_argument("b", type=float, help="Second number")
parser.add_argument(
"-o", "--operation",
choices=["add", "sub", "mul", "div"],
default="add",
help="Math operation (default: add)"
)
args = parser.parse_args()
if args.operation == "add":
result = args.a + args.b
elif args.operation == "sub":
result = args.a - args.b
elif args.operation == "mul":
result = args.a * args.b
elif args.operation == "div":
result = args.a / args.b
print(result)
if __name__ == "__main__":
main()
Теперь можно запускать:
python calc.py 2 3
python calc.py 10 5 -o sub
python calc.py 3 4 --operation mul
argparse уже умеет:- показывать
--help с описанием- проверять типы (
type=float)- ограничивать значения (
choices=[...])- задавать значения по умолчанию (
default=)---
### Пара фишек, которые часто забывают
1. Флаг без значения — просто наличие/отсутствие:
parser.add_argument(
"-v", "--verbose",
action="store_true",
help="Show detailed output"
)
Теперь
--verbose даёт args.verbose == True.2. Переиспользование логики
Лучше выносить «деловую» логику в отдельные функции — тогда скрипт проще тестировать и расширять:
def calculate(a, b, operation):
if operation == "add":
return a + b
if operation == "sub":
return a - b
if operation == "mul":
return a * b
if operation == "div":
return a / b
raise ValueError("Unknown operation")
---
CLI-инструмент в Python — это буквально несколько строк с
argparse, а ощущение уже как от «настоящей» утилиты. Попробуйте переписать свой следующий скрипт так, чтобы он принимал аргументы командной строки — разница в удобстве будет огромной.👍3🔥1
Python для начинающих: как подружиться с постраничной загрузкой из API
Если вы когда‑нибудь тянули данные из API, то почти наверняка сталкивались с ситуацией: «Тут 10 записей, а где остальные 10 000?». Ответ — в пагинации (postраничной загрузке). API редко отдают всё сразу, чтобы не положить ни себя, ни вас.
Разберёмся, какие бывают схемы пагинации и как с ними работать в Python.
---
### 1. Пагинация по номеру страницы
Классика: у вас есть
Ключевой момент — условие выхода. Часто API возвращает
---
### 2. Пагинация по смещению (offset/limit)
Тут вам дают
Минус offset-подхода — при больших объёмах данных он может быть медленнее.
---
### 3. Пагинация по курсору (cursor / next)
Самый «современный» вариант: API возвращает ссылку или токен для следующей страницы.
Здесь нет ни страниц, ни offset — только
---
### Полезные рекомендации
- Всегда ставьте
- Уважайте лимиты API: иногда нужно делать
- Логируйте прогресс:
Понимая три паттерна пагинации —
Если вы когда‑нибудь тянули данные из API, то почти наверняка сталкивались с ситуацией: «Тут 10 записей, а где остальные 10 000?». Ответ — в пагинации (postраничной загрузке). API редко отдают всё сразу, чтобы не положить ни себя, ни вас.
Разберёмся, какие бывают схемы пагинации и как с ними работать в Python.
---
### 1. Пагинация по номеру страницы
Классика: у вас есть
page и per_page.import requests
BASE_URL = "https://api.example.com/items"
def fetch_page(page: int, per_page: int = 50):
params = {"page": page, "per_page": per_page}
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status()
return response.json()
def fetch_all_items():
page = 1
all_items = []
while True:
data = fetch_page(page)
items = data.get("items", [])
if not items:
break
all_items.extend(items)
if not data.get("has_next"): # или проверяем page >= total_pages
break
page += 1
return all_items
Ключевой момент — условие выхода. Часто API возвращает
has_next, total_pages или next_page.---
### 2. Пагинация по смещению (offset/limit)
Тут вам дают
offset (сдвиг) и limit (размер пачки):def fetch_batch(offset: int, limit: int = 100):
params = {"offset": offset, "limit": limit}
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status()
return response.json()
def fetch_all_items_offset():
offset = 0
limit = 100
all_items = []
while True:
data = fetch_batch(offset, limit)
items = data.get("items", [])
if not items:
break
all_items.extend(items)
offset += limit
return all_items
Минус offset-подхода — при больших объёмах данных он может быть медленнее.
---
### 3. Пагинация по курсору (cursor / next)
Самый «современный» вариант: API возвращает ссылку или токен для следующей страницы.
def fetch_all_items_cursor():
url = BASE_URL
all_items = []
while url:
response = requests.get(url, timeout=10)
response.raise_for_status()
data = response.json()
items = data.get("items", [])
all_items.extend(items)
url = data.get("next") # None, если страниц больше нет
return all_items
Здесь нет ни страниц, ни offset — только
next. Это устойчиво к изменениям данных на сервере.---
### Полезные рекомендации
- Всегда ставьте
timeout в requests.get.- Уважайте лимиты API: иногда нужно делать
time.sleep() между запросами.- Логируйте прогресс:
len(all_items) поможет понять, что вы действительно двигаетесь.Понимая три паттерна пагинации —
page, offset, cursor — вы сможете уверенно забирать из API тысячи и миллионы записей, не утонув ни в ошибках, ни в лимитах.👍3
Работа с форматом YAML в Python с использованием PyYAML
YAML любят за читаемость: в отличие от JSON, здесь меньше скобок и больше структуры за счёт отступов. Его часто используют для конфигов, docker-compose, GitHub Actions и т.д. Давайте посмотрим, как работать с YAML в Python с помощью библиотеки PyYAML.
Установка:
---
## Базовая загрузка YAML
Пусть у нас есть файл
Прочитаем его:
---
## Запись данных в YAML
Сериализуем Python-объекты обратно в YAML:
Параметр
---
## Работа со списками и вложенностью
PyYAML без проблем понимает сложные структуры:
---
## Кастомные типы через теги
YAML поддерживает теги вроде
Так можно описывать конфиги, которые сразу превращаются в модели вашего приложения.
---
PyYAML — мощный и при этом простой инструмент: он позволяет читать и писать конфиги, работать со сложными структурами и даже маппить YAML на классы Python. Если вы часто имеете дело с настройками и инфраструктурой — эта библиотека станет обязательным пунктом в вашем наборе инструментов.
YAML любят за читаемость: в отличие от JSON, здесь меньше скобок и больше структуры за счёт отступов. Его часто используют для конфигов, docker-compose, GitHub Actions и т.д. Давайте посмотрим, как работать с YAML в Python с помощью библиотеки PyYAML.
Установка:
pip install pyyaml
---
## Базовая загрузка YAML
Пусть у нас есть файл
config.yml:app:
name: "MyApp"
debug: true
version: 1.0
database:
host: "localhost"
port: 5432
tags:
- primary
- readonly
Прочитаем его:
import yaml
with open("config.yml", "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
print(config["app"]["name"]) # MyApp
print(config["database"]["tags"]) # ['primary', 'readonly']
safe_load — безопасный вариант парсинга, его и стоит использовать почти всегда.---
## Запись данных в YAML
Сериализуем Python-объекты обратно в YAML:
import yaml
settings = {
"app": {"name": "NewApp", "debug": False},
"features": ["auth", "billing", "reports"]
}
with open("settings.yml", "w", encoding="utf-8") as f:
yaml.safe_dump(settings, f, sort_keys=False, allow_unicode=True)
Параметр
sort_keys=False сохраняет порядок ключей, а allow_unicode=True позволяет писать не только ASCII.---
## Работа со списками и вложенностью
PyYAML без проблем понимает сложные структуры:
import yaml
yaml_str = """
users:
- name: "Alice"
roles: ["admin", "editor"]
- name: "Bob"
roles:
- "viewer"
- "auditor"
"""
data = yaml.safe_load(yaml_str)
admins = [u["name"] for u in data["users"] if "admin" in u["roles"]]
print(admins) # ['Alice']
---
## Кастомные типы через теги
YAML поддерживает теги вроде
!MyTag. С их помощью можно превращать YAML-данные сразу в объекты Python.import yaml
from dataclasses import dataclass
@dataclass
class User:
name: str
level: int
def user_constructor(loader, node):
values = loader.construct_mapping(node)
return User(**values)
yaml.add_constructor("!User", user_constructor)
yaml_str = """
user: !User
name: "Alice"
level: 5
"""
data = yaml.safe_load(yaml_str)
print(data["user"]) # User(name='Alice', level=5)
print(data["user"].level) # 5
Так можно описывать конфиги, которые сразу превращаются в модели вашего приложения.
---
PyYAML — мощный и при этом простой инструмент: он позволяет читать и писать конфиги, работать со сложными структурами и даже маппить YAML на классы Python. Если вы часто имеете дело с настройками и инфраструктурой — эта библиотека станет обязательным пунктом в вашем наборе инструментов.
👍3🔥1
Изучение модуля
Большинство начинающих знают только
### Зачем нужен
- выполнить задачу через некоторое время;
- запланировать серию событий;
- управлять порядком выполнения задач во времени.
При этом он не блокирует весь код сам по себе — вы сами решаете, когда запустить обработку событий.
### Базовый пример
Что здесь происходит:
-
-
-
Через 3 секунды вы увидите приветствие и текущий timestamp.
### Приоритеты и несколько задач
Обе задачи запланированы через 5 секунд, но сначала выполнится та, у которой
### Отложенные и повторяющиеся задачи
Повторения можно организовать вручную — внутри функции заново планировать саму себя:
Здесь первая задача стартует через 1 секунду, а затем каждые 2 секунды перепланирует себя.
### Когда использовать
- простого планирования задач в одном потоке;
- тестов и симуляций событий во времени;
- ситуаций, где нужен контроль над порядком выполнения и временем.
Если нужно:
- сложное расписание (крон-подобное);
- работа с разными часовыми поясами, датами, календарями;
- продвинутая асинхронность,
то лучше посмотреть в сторону
Но для понимания базовых принципов планирования задач во времени
sched: планирование задач во времениБольшинство начинающих знают только
time.sleep() и думают, что этим инструменты по работе со временем заканчиваются. Но в стандартной библиотеке Python есть модуль sched, который позволяет строить мини-планировщик задач — почти как будильник, но для кода.### Зачем нужен
sched?sched удобен, когда нужно:- выполнить задачу через некоторое время;
- запланировать серию событий;
- управлять порядком выполнения задач во времени.
При этом он не блокирует весь код сам по себе — вы сами решаете, когда запустить обработку событий.
### Базовый пример
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def say_hello(name):
print(f"Hello, {name}! Time:", time.time())
print("Start:", time.time())
scheduler.enter(3, 1, say_hello, argument=("Alice",))
scheduler.run()
print("End:", time.time())
Что здесь происходит:
-
sched.scheduler(time.time, time.sleep) — создаем планировщик, который знает «что такое сейчас» и «как подождать».-
enter(delay, priority, action, argument=...) — выполняет action через delay секунд.-
scheduler.run() — запускает цикл обработки событий (блокирует поток до выполнения всех задач).Через 3 секунды вы увидите приветствие и текущий timestamp.
### Приоритеты и несколько задач
priority пригодится, когда два события должны выполниться в одно и то же время.import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def log(msg):
print(time.time(), msg)
scheduler.enter(5, 2, log, argument=("low priority",))
scheduler.enter(5, 1, log, argument=("high priority",))
scheduler.run()
Обе задачи запланированы через 5 секунд, но сначала выполнится та, у которой
priority=1.### Отложенные и повторяющиеся задачи
Повторения можно организовать вручную — внутри функции заново планировать саму себя:
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def periodic_task(interval):
print("Tick at", time.time())
scheduler.enter(interval, 1, periodic_task, argument=(interval,))
scheduler.enter(1, 1, periodic_task, argument=(2,))
scheduler.run()
Здесь первая задача стартует через 1 секунду, а затем каждые 2 секунды перепланирует себя.
### Когда использовать
sched, а когда нетsched хорош для:- простого планирования задач в одном потоке;
- тестов и симуляций событий во времени;
- ситуаций, где нужен контроль над порядком выполнения и временем.
Если нужно:
- сложное расписание (крон-подобное);
- работа с разными часовыми поясами, датами, календарями;
- продвинутая асинхронность,
то лучше посмотреть в сторону
APScheduler, asyncio или системного cron.Но для понимания базовых принципов планирования задач во времени
sched — идеальный старт, да еще и без сторонних библиотек.👍4
Инструменты отладки кода: знакомство с модулем
Большинство новичков отлаживают код методом «print по всему файлу». Это работает, пока проект маленький. Но как только логика усложняется, принты превращают код в хаос. Пора знакомиться с встроенным отладчиком Python — модулем
---
## Что такое
- ставить точки останова (breakpoints);
- пошагово выполнять код;
- смотреть значения переменных «изнутри» функции;
- менять состояние программы на лету.
И все это — прямо в терминале, без IDE.
---
## Базовый пример:
Допустим, у нас странная функция, которая считает среднее, но иногда падает с ошибкой:
Запускаем:
На строке с
Теперь можно управлять выполнением.
---
## Минимальный набор команд
Внутри отладчика доступны команды:
-
-
-
-
-
-
Например, из нашего примера:
Можно зайти внутрь
И уже там:
Так легко найти момент, когда
---
## Breakpoint без импорта: встроенная функция
Начиная с Python 3.7 есть удобный шорткат:
Функция
---
## Отладка конкретного файла через
Иногда не хочется править код и вставлять
---
pdbБольшинство новичков отлаживают код методом «print по всему файлу». Это работает, пока проект маленький. Но как только логика усложняется, принты превращают код в хаос. Пора знакомиться с встроенным отладчиком Python — модулем
pdb.---
## Что такое
pdb и зачем он нуженpdb позволяет:- ставить точки останова (breakpoints);
- пошагово выполнять код;
- смотреть значения переменных «изнутри» функции;
- менять состояние программы на лету.
И все это — прямо в терминале, без IDE.
---
## Базовый пример:
pdb.set_trace()Допустим, у нас странная функция, которая считает среднее, но иногда падает с ошибкой:
import pdb
def avg(values):
total = 0
count = 0
for v in values:
total += v
count += 1
return total / count
data = [10, 20, 0, "oops", 40]
pdb.set_trace() # точка останова
result = avg(data)
print(result)
Запускаем:
python script.py
На строке с
set_trace() программа остановится, и вы увидите приглашение вида:(Pdb)
Теперь можно управлять выполнением.
---
## Минимальный набор команд
pdbВнутри отладчика доступны команды:
-
l — (list) показать код вокруг текущей строки;-
n — (next) выполнить следующую строку в текущей функции;-
s — (step) шаг внутрь вызываемой функции;-
c — (continue) продолжить выполнение до следующего breakpoint;-
p expr — (print) напечатать выражение, например p data;-
q — (quit) выйти из отладчика.Например, из нашего примера:
(Pdb) p data
[10, 20, 0, 'oops', 40]
(Pdb) n
Можно зайти внутрь
avg:(Pdb) s
И уже там:
(Pdb) p v
10
(Pdb) n
(Pdb) p total
10
Так легко найти момент, когда
v внезапно становится строкой "oops" и ломает вычисления.---
## Breakpoint без импорта: встроенная функция
breakpoint()Начиная с Python 3.7 есть удобный шорткат:
def calc_sum(values):
s = 0
for v in values:
s += v
return s
data = [1, 2, 3]
breakpoint() # работает как pdb.set_trace() по умолчанию
print(calc_sum(data))
Функция
breakpoint() смотрит на переменную окружения PYTHONBREAKPOINT, поэтому при желании можно подменять стандартный отладчик.---
## Отладка конкретного файла через
-m pdbИногда не хочется править код и вставлять
set_trace(). Можно запустить файл целиком через pdb:python -m pdb script.py
pdb сразу загрузит файл, поставит breakpoint на первой строке, и дальше вы будете управлять выполнением командами n, s, c и т.д.---
pdb — это минимальный, но мощный инструмент, который стоит освоить как можно раньше. Он дисциплинирует мышление: вместо хаотичных принтов вы начинаете осознанно исследовать состояние программы и понимать, почему она ведет себя так, а не иначе.❤3👍1
Как работать с цветом в терминале: библиотека
Текстовый вывод в консоль необязательно должен быть скучным. Цвет помогает выделять ошибки, предупреждения, важные шаги и просто делает скрипт понятнее. В Python это удобно делать с помощью библиотеки colorama.
---
## Установка и базовое использование
Установим библиотеку:
Минимальный пример:
---
## Ручной контроль сброса
Если нужно более тонко управлять стилем:
Так можно красить только часть строки и точно контролировать, где стиль заканчивается.
---
## Цветной логгер своими руками
Сделаем простой цветной вывод по уровням:
Такой мини-логгер уже заметно улучшает читаемость вывода, особенно в длинных скриптах.
---
## Кроссплатформенность
Главный плюс
- на Windows (преобразует ANSI-коды в понятные для консоли команды),
- в Linux и macOS (где ANSI уже поддерживаются).
То есть вы один раз пишете цветной вывод — и не думаете о том, на какой системе будет запускаться ваш скрипт.
---
Попробуйте добавить
coloramaТекстовый вывод в консоль необязательно должен быть скучным. Цвет помогает выделять ошибки, предупреждения, важные шаги и просто делает скрипт понятнее. В Python это удобно делать с помощью библиотеки colorama.
---
## Установка и базовое использование
Установим библиотеку:
pip install colorama
Минимальный пример:
from colorama import init, Fore, Back, Style
init(autoreset=True)
print(Fore.RED + "Error: something went wrong")
print(Fore.GREEN + "Success: all tests passed")
print(Back.YELLOW + Fore.BLACK + "Warning: check your settings")
print(Style.DIM + "This is a dim text")
print(Style.BRIGHT + "This is a bright text")
init(autoreset=True) автоматически сбрасывает цвет после каждой строки, чтобы не красить весь терминал случайно.---
## Ручной контроль сброса
Если нужно более тонко управлять стилем:
from colorama import init, Fore, Style
init(autoreset=False)
print(Fore.CYAN + "Step 1:", Style.RESET_ALL, "download data")
print(Fore.MAGENTA + "Step 2:", Style.RESET_ALL, "process data")
print(Fore.RED + "Critical message", end="")
print(Style.RESET_ALL) # сбросили только здесь
Так можно красить только часть строки и точно контролировать, где стиль заканчивается.
---
## Цветной логгер своими руками
Сделаем простой цветной вывод по уровням:
from colorama import init, Fore, Style
init(autoreset=True)
def log(message, level="info"):
if level == "info":
color = Fore.CYAN
elif level == "warning":
color = Fore.YELLOW
elif level == "error":
color = Fore.RED + Style.BRIGHT
else:
color = Fore.WHITE
print(color + f"[{level.upper()}] {message}")
log("Application started", "info")
log("Low disk space", "warning")
log("Unable to connect to database", "error")
Такой мини-логгер уже заметно улучшает читаемость вывода, особенно в длинных скриптах.
---
## Кроссплатформенность
Главный плюс
colorama — он одинаково работает:- на Windows (преобразует ANSI-коды в понятные для консоли команды),
- в Linux и macOS (где ANSI уже поддерживаются).
То есть вы один раз пишете цветной вывод — и не думаете о том, на какой системе будет запускаться ваш скрипт.
---
Попробуйте добавить
colorama в свои маленькие утилиты: подсветите ошибки, выделите успешные шаги, сделайте прогресс более наглядным. Цвет в консоли — это простой инструмент, который заметно повышает удобство работы с программой.👍5
Парсинг командной строки с помощью
Когда скрипт перестаёт быть «одноразовым файлом» и превращается в инструмент, ему срочно нужны параметры командной строки. Флаги вроде
В Python для этого исторически есть два модуля: «олдскульный»
---
##
Плюсы: минимальные зависимости и поведение, знакомое по Unix.
Минусы: вручную писать help, валидировать значения, обрабатывать ошибки.
---
##
Запустите:
- разберёт параметры,
- покажет аккуратный help,
- выдаст понятную ошибку, если аргументы неверны.
---
### Что выбрать?
- Небольшие утилиты, где нужен лишь парочка флагов и вы любите POSIX-стиль — можно
- Любой скрипт, который должны читать и использовать другие люди (а часто и вы сами через месяц) — однозначно
Если ваш Python-скрипт ещё запускается как
getopt и argparseКогда скрипт перестаёт быть «одноразовым файлом» и превращается в инструмент, ему срочно нужны параметры командной строки. Флаги вроде
--input data.csv или -v делают ваш код удобным, автоматизируемым и… чуть менее хаотичным.В Python для этого исторически есть два модуля: «олдскульный»
getopt и современный, почти стандарт де-факто — argparse.---
##
getopt: минимализм в стиле POSIXgetopt напоминает классический getopt из C. Он прост, если вам нужны только короткие флаги и немного логики.import sys
import getopt
def main():
short_opts = "hi:o:"
long_opts = ["help", "input=", "output="]
try:
opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
except getopt.GetoptError as err:
print(err)
sys.exit(2)
input_file = None
output_file = None
for opt, val in opts:
if opt in ("-h", "--help"):
print("Usage: script.py -i <input> -o <output>")
sys.exit()
elif opt in ("-i", "--input"):
input_file = val
elif opt in ("-o", "--output"):
output_file = val
print("Input:", input_file)
print("Output:", output_file)
print("Positional args:", args)
if __name__ == "__main__":
main()
Плюсы: минимальные зависимости и поведение, знакомое по Unix.
Минусы: вручную писать help, валидировать значения, обрабатывать ошибки.
---
##
argparse: когда хочется «по-взрослому»argparse создаёт полноценный CLI почти без лишнего кода: автоматический --help, валидация типов, значения по умолчанию, подкоманды.import argparse
def main():
parser = argparse.ArgumentParser(
description="Resize image with given scale"
)
parser.add_argument("path", help="Path to image file")
parser.add_argument("-s", "--scale", type=float, default=1.0,
help="Resize scale (default: 1.0)")
parser.add_argument("-v", "--verbose", action="store_true",
help="Enable verbose output")
args = parser.parse_args()
if args.verbose:
print(f"Loading image from {args.path}")
print(f"Scale factor: {args.scale}")
# here could be real image processing
print("Resized successfully")
if __name__ == "__main__":
main()
Запустите:
python script.py photo.jpg -s 0.5 -v
python script.py --help
argparse сам:- разберёт параметры,
- покажет аккуратный help,
- выдаст понятную ошибку, если аргументы неверны.
---
### Что выбрать?
- Небольшие утилиты, где нужен лишь парочка флагов и вы любите POSIX-стиль — можно
getopt.- Любой скрипт, который должны читать и использовать другие люди (а часто и вы сами через месяц) — однозначно
argparse.Если ваш Python-скрипт ещё запускается как
python script.py без параметров — самое время превратить его в инструмент, а не в лотерею с input() и захардкоженными путями.👍3❤1
### Python для начинающих: создаем красивый прогресс-бар с
Когда скрипт «думает» дольше пары секунд, пользователь начинает волноваться: «Он вообще работает или уже завис?». Прогресс-бар в терминале решает эту проблему — и модуль
---
## Установка
---
## Базовый пример
Минимальный прогресс-бар для цикла:
Что происходит:
-
- выводит прогресс, процент, скорость и время до окончания.
---
## Прогресс-бар для списков и генераторов
Аргумент
---
## Ручное обновление прогресса
Если у вас нет удобного итератора (например, цикл внутри функции), можно обновлять прогресс вручную:
Здесь:
-
-
---
## Обёртка для функций:
Если вы обрабатываете коллекцию с помощью
Важный момент: для
---
## Быстрый чек-лист по
- Подходит для любых итерируемых объектов.
- Умеет считать время, скорость и ETA.
- Можно использовать как контекстный менеджер и обновлять вручную.
- Практически не требует изменений логики программы.
Попробуйте добавить
tqdmКогда скрипт «думает» дольше пары секунд, пользователь начинает волноваться: «Он вообще работает или уже завис?». Прогресс-бар в терминале решает эту проблему — и модуль
tqdm делает это буквально одной строкой кода.---
## Установка
tqdm не входит в стандартную библиотеку, его нужно установить:pip install tqdm
---
## Базовый пример
Минимальный прогресс-бар для цикла:
from time import sleep
from tqdm import tqdm
for i in tqdm(range(100)):
sleep(0.05) # имитация работы
Что происходит:
-
tqdm(iterable) оборачивает любой итерируемый объект (range, список, генератор);- выводит прогресс, процент, скорость и время до окончания.
---
## Прогресс-бар для списков и генераторов
tqdm не требует именно range. Можно использовать списки:from time import sleep
from tqdm import tqdm
files = ["data1.csv", "data2.csv", "data3.csv"]
for filename in tqdm(files, desc="Processing"):
sleep(0.5) # обработка файла
Аргумент
desc добавляет понятное описание слева от прогресс-бара.---
## Ручное обновление прогресса
Если у вас нет удобного итератора (например, цикл внутри функции), можно обновлять прогресс вручную:
from time import sleep
from tqdm import tqdm
total_steps = 5
with tqdm(total=total_steps, desc="Custom task") as pbar:
for step in range(total_steps):
sleep(0.7) # тяжелая операция
pbar.update(1)
Здесь:
-
total — общее количество шагов;-
pbar.update(n) — сообщаем, что выполнено n шагов.---
## Обёртка для функций:
tqdm + mapЕсли вы обрабатываете коллекцию с помощью
map, можно добавить прогресс почти без изменений кода:from time import sleep
from tqdm import tqdm
def process_item(item):
sleep(0.2)
return item * 2
items = list(range(50))
results = list(tqdm(map(process_item, items), total=len(items)))
Важный момент: для
map нужно явно указать total=len(items), иначе tqdm не знает, сколько всего элементов.---
## Быстрый чек-лист по
tqdm- Подходит для любых итерируемых объектов.
- Умеет считать время, скорость и ETA.
- Можно использовать как контекстный менеджер и обновлять вручную.
- Практически не требует изменений логики программы.
Попробуйте добавить
tqdm в ваш текущий скрипт с долгими циклами — и терминал сразу станет дружелюбнее для пользователя… и для вас.👍4🔥1
Изучение модуля
Когда речь заходит о безопасности и уникальной идентификации данных в Python, почти всегда всплывает модуль
### Что такое хеш?
Хеш-функция берет любые данные (строку, файл, пароль) и превращает их в строку фиксированной длины. Малейшее изменение исходных данных кардинально меняет хеш — это удобно для проверки целостности.
### Первый пример: хеш строки
Попробуйте поменять хотя бы один символ в
### Проверка целостности данных
Допустим, вы скачали файл и хотите убедиться, что он не поврежден. Принцип тот же — считаем хеш и сравниваем.
Здесь мы читаем файл по частям, чтобы не загружать его целиком в память (важно для больших файлов).
### Хеш пароля (но по‑простому)
Подчеркиваю: это упрощенный подход для понимания, а не готовое решение для продакшена.
Зачем
### Быстрый обзор алгоритмов
Самые используемые:
Для новых проектов
---
hashlib: простое хеширование данныхКогда речь заходит о безопасности и уникальной идентификации данных в Python, почти всегда всплывает модуль
hashlib. Он не шифрует данные (это важно!), а превращает их в «отпечаток» — фиксированную строку, по которой нельзя восстановить оригинал, но можно проверить, не изменился ли он.### Что такое хеш?
Хеш-функция берет любые данные (строку, файл, пароль) и превращает их в строку фиксированной длины. Малейшее изменение исходных данных кардинально меняет хеш — это удобно для проверки целостности.
### Первый пример: хеш строки
import hashlib
text = "Hello, hashlib!"
text_bytes = text.encode("utf-8") # хешируем всегда байты
hash_object = hashlib.sha256(text_bytes)
hash_hex = hash_object.hexdigest()
print(hash_hex)
sha256 — один из популярных алгоритмов. Метод .hexdigest() возвращает хеш в виде удобной шестнадцатеричной строки.Попробуйте поменять хотя бы один символ в
text — длина хеша останется той же, но значение полностью изменится.### Проверка целостности данных
Допустим, вы скачали файл и хотите убедиться, что он не поврежден. Принцип тот же — считаем хеш и сравниваем.
import hashlib
def file_hash(path, algorithm="sha256", chunk_size=8192):
hash_obj = getattr(hashlib, algorithm)()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
hash_obj.update(chunk)
return hash_obj.hexdigest()
print(file_hash("example.txt"))
Здесь мы читаем файл по частям, чтобы не загружать его целиком в память (важно для больших файлов).
### Хеш пароля (но по‑простому)
Подчеркиваю: это упрощенный подход для понимания, а не готовое решение для продакшена.
import hashlib
def hash_password(password: str, salt: str) -> str:
data = (password + salt).encode("utf-8")
return hashlib.sha256(data).hexdigest()
password_hash = hash_password("my_secret_password", "random_salt_123")
print(password_hash)
Зачем
salt? Без него одинаковые пароли у разных пользователей давали бы одинаковые хеши. Соль делает результат уникальным.### Быстрый обзор алгоритмов
import hashlib
print(hashlib.algorithms_guaranteed)
Самые используемые:
md5, sha1, sha224, sha256, sha384, sha512. Для новых проектов
md5 и sha1 уже считаются слабыми для безопасности, но всё ещё полезны для простой проверки целостности (там, где нет угрозы взлома).---
hashlib — отличный инструмент, чтобы аккуратно и предсказуемо «упаковывать» данные в компактные отпечатки. Понимание хеширования — обязательный шаг на пути к более продвинутым темам: аутентификация, токены, работа с файлами и безопасностью в целом.🔥4👍1
### Работа с zip-архивами с помощью стандартного
Zip-архивы — это такой «контейнер» для файлов: удобно отправить, сохранить, логировать бэкапы. В Python для этого ничего устанавливать не нужно — в стандартной библиотеке уже есть модуль
---
## Создаем zip-архив
Начнем с базового: упакуем несколько файлов в один архив.
Ключевые моменты:
-
-
-
---
## Добавляем файлы в существующий архив
Иногда нужно дописать архив, не пересоздавая его:
Режим
---
## Просмотр содержимого архива
Посмотрим, что внутри, без распаковки:
Объект
---
## Распаковка архива
Распакуем либо всё, либо один конкретный файл:
---
## Чтение файла прямо из архива
Иногда распаковывать на диск не хочется — удобнее прочитать файл «на лету»:
Так можно, например, читать настройки, ресурсы или шаблоны прямо из архива.
---
zipfileZip-архивы — это такой «контейнер» для файлов: удобно отправить, сохранить, логировать бэкапы. В Python для этого ничего устанавливать не нужно — в стандартной библиотеке уже есть модуль
zipfile.---
## Создаем zip-архив
Начнем с базового: упакуем несколько файлов в один архив.
import zipfile
from pathlib import Path
def create_archive(archive_name, files):
with zipfile.ZipFile(archive_name, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
for file_path in files:
file_path = Path(file_path)
zf.write(file_path, arcname=file_path.name)
create_archive("project.zip", ["main.py", "config.json", "README.md"])
Ключевые моменты:
-
mode="w" — создать новый архив (старый с таким именем будет перезаписан).-
compression=ZIP_DEFLATED — сжатие, без него файлы просто «складываются» в контейнер.-
arcname — имя файла внутри архива (можно отличать от исходного пути).---
## Добавляем файлы в существующий архив
Иногда нужно дописать архив, не пересоздавая его:
import zipfile
def append_to_archive(archive_name, file_path):
with zipfile.ZipFile(archive_name, mode="a", compression=zipfile.ZIP_DEFLATED) as zf:
zf.write(file_path)
append_to_archive("project.zip", "log.txt")
Режим
a — «append», дозапись.---
## Просмотр содержимого архива
Посмотрим, что внутри, без распаковки:
import zipfile
def list_archive(archive_name):
with zipfile.ZipFile(archive_name, mode="r") as zf:
for info in zf.infolist():
print(f"{info.filename:20} {info.file_size:8} bytes")
list_archive("project.zip")
Объект
ZipInfo содержит размер, дату изменения, атрибуты и т.д.---
## Распаковка архива
Распакуем либо всё, либо один конкретный файл:
import zipfile
def extract_all(archive_name, target_dir):
with zipfile.ZipFile(archive_name, mode="r") as zf:
zf.extractall(path=target_dir)
def extract_file(archive_name, member, target_dir):
with zipfile.ZipFile(archive_name, mode="r") as zf:
zf.extract(member, path=target_dir)
extract_all("project.zip", "unpacked/")
extract_file("project.zip", "config.json", "configs/")
---
## Чтение файла прямо из архива
Иногда распаковывать на диск не хочется — удобнее прочитать файл «на лету»:
import zipfile
def read_text_from_zip(archive_name, member):
with zipfile.ZipFile(archive_name, mode="r") as zf:
with zf.open(member) as f:
return f.read().decode("utf-8")
content = read_text_from_zip("project.zip", "README.md")
print(content)
Так можно, например, читать настройки, ресурсы или шаблоны прямо из архива.
---
zipfile покрывает 90% бытовых задач с архивами: упаковка, дописывание, просмотр, извлечение и чтение «на лету». Всё это — без сторонних библиотек и с парой строк кода.👍6
Как использовать модуль
Иногда Python‑кода мало. Нужно дернуть системную утилиту: запустить
---
### Простой запуск и получение вывода
Самый удобный вход — функция
Ключевые моменты:
- Команда передаётся как список:
-
-
---
### Обработка ошибок
Если вы хотите, чтобы Python падал при ошибке команды, используйте
---
### Передача данных на stdin
Иногда внешней программе нужно что‑то «скормить» через стандартный ввод:
Параметр
---
### Непосредственное взаимодействие:
Если нужно более тонкое управление (долгоживущий процесс, чтение вывода построчно и т.п.), используйте
Здесь процесс живет «параллельно», а вы можете читать его вывод по мере поступления.
---
### Кратко по безопасности
- Не передавайте в
- Предпочитайте список аргументов вместо одной строки.
- Не включайте
---
subprocess для запуска внешних командИногда Python‑кода мало. Нужно дернуть системную утилиту: запустить
ping, запустить другой скрипт, конвертировать видео через ffmpeg. Для этого есть модуль subprocess — безопасная и гибкая альтернатива старым os.system.---
### Простой запуск и получение вывода
Самый удобный вход — функция
subprocess.run. Она запускает команду, ждет завершения и возвращает объект с результатом:import subprocess
result = subprocess.run(
["echo", "Hello from subprocess"],
capture_output=True,
text=True
)
print("Return code:", result.returncode)
print("Stdout:", result.stdout)
print("Stderr:", result.stderr)
Ключевые моменты:
- Команда передаётся как список:
["echo", "text"], а не одной строкой. Это безопаснее и избавляет от проблем с кавычками.-
capture_output=True собирает stdout и stderr.-
text=True декодирует байты в строки (по умолчанию UTF-8).---
### Обработка ошибок
Если вы хотите, чтобы Python падал при ошибке команды, используйте
check=True:import subprocess
try:
subprocess.run(
["ls", "/definitely_not_exists"],
check=True,
capture_output=True,
text=True
)
except subprocess.CalledProcessError as exc:
print("Command failed!")
print("Return code:", exc.returncode)
print("Stderr:", exc.stderr)
CalledProcessError содержит всю полезную информацию о провалившейся команде.---
### Передача данных на stdin
Иногда внешней программе нужно что‑то «скормить» через стандартный ввод:
import subprocess
text_to_send = "line 1\nline 2\n"
result = subprocess.run(
["grep", "line"],
input=text_to_send,
text=True,
capture_output=True
)
print(result.stdout)
Параметр
input= передает данные в stdin процесса.---
### Непосредственное взаимодействие:
PopenЕсли нужно более тонкое управление (долгоживущий процесс, чтение вывода построчно и т.п.), используйте
Popen:import subprocess
proc = subprocess.Popen(
["ping", "-c", "3", "python.org"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
for line in proc.stdout:
print("PING OUTPUT:", line.strip())
return_code = proc.wait()
print("Return code:", return_code)
Здесь процесс живет «параллельно», а вы можете читать его вывод по мере поступления.
---
### Кратко по безопасности
- Не передавайте в
subprocess строки, собранные из непроверенного пользовательского ввода.- Предпочитайте список аргументов вместо одной строки.
- Не включайте
shell=True, если это не абсолютно необходимо. Именно shell=True чаще всего открывает дверь инъекциям команд.---
subprocess — это мост между вашим Python‑кодом и всем остальным миром командной строки. Освоив его, вы сможете автоматизировать практически любую системную задачу, не покидая Python.👍5