Разбор стандартного модуля
Модуль
---
##
Обычный список в Python плохо подходит для частых операций в начале:
---
##
Обычный словарь бросает
Другой частый сценарий — группировка:
---
##
Отлично подходит для анализа текста:
---
Итог:
-
-
-
Все три входят в стандартную библиотеку, не требуют установки и моментально делают код чище и эффективнее. Попробуйте в своих маленьких скриптах — разницу почувствуете сразу.
collections: deque, defaultdict и CounterМодуль
collections — это такой «апгрейд» стандартных структур данных в Python. Те же списки и словари, но с турбонаддувом. Разберём три самых полезных инструмента: deque, defaultdict и Counter.---
##
deque: очередь без мученийОбычный список в Python плохо подходит для частых операций в начале:
pop(0) и insert(0, x) работают медленно. deque (double-ended queue) решает это.from collections import deque
queue = deque()
queue.append('task_1')
queue.append('task_2')
queue.appendleft('urgent_task')
print(queue) # deque(['urgent_task', 'task_1', 'task_2'])
task = queue.popleft() # достаем слева O(1)
print(task) # urgent_task
deque идеально подходит для очередей, буферов, реализации алгоритмов обхода графов (BFS) и «скользящих окон».---
##
defaultdict: словарь, который не ругаетсяОбычный словарь бросает
KeyError, если ключа нет. defaultdict вместо этого создаёт значение «по умолчанию».from collections import defaultdict
word_count = defaultdict(int)
text = "python is fun and python is powerful".split()
for word in text:
word_count[word] += 1
print(word_count['python']) # 2
print(word_count['missing']) # 0, а не KeyError
Другой частый сценарий — группировка:
from collections import defaultdict
groups = defaultdict(list)
pairs = [('a', 1), ('b', 2), ('a', 3)]
for key, value in pairs:
groups[key].append(value)
print(groups) # {'a': [1, 3], 'b': [2]}
---
##
Counter: просто посчитай этоCounter — специализированный словарь для подсчёта объектов.from collections import Counter
nums = [1, 2, 2, 3, 3, 3]
c = Counter(nums)
print(c) # Counter({3: 3, 2: 2, 1: 1})
print(c[2]) # 2
print(c.most_common(1))# [(3, 3)]
Отлично подходит для анализа текста:
from collections import Counter
text = "banana bandana"
c = Counter(text.replace(" ", ""))
print(c) # Counter({'a': 6, 'n': 3, 'b': 1, 'd': 1})
print(c.most_common(2))# самые частые буквы
---
Итог:
-
deque — быстрая очередь с двух концов. -
defaultdict — словарь с автоматическими значениями по умолчанию. -
Counter — быстрый подсчёт повторяющихся элементов.Все три входят в стандартную библиотеку, не требуют установки и моментально делают код чище и эффективнее. Попробуйте в своих маленьких скриптах — разницу почувствуете сразу.
👍4
### Создание простого REST API с Falcon: минимализм в деле
Если Flask — это швейцарский нож, то Falcon — это скальпель. Минимум магии, максимум скорости и простоты. Он отлично подходит, когда нужно сделать легкий REST API без нагромождений.
---
## Установка
Falcon не входит в стандартную библиотеку, ставим:
---
## Базовый пример: «Hello, API»
Создадим минимальный REST API, который отвечает JSON-ом.
Сохрани файл как
Переходим по
---
## Обработка методов: GET и POST
Добавим ресурс для работы со списком задач. Хранить будем в памяти, как простой пример.
Теперь:
-
-
---
## Обработка одного ресурса по ID
Добавим получение одной задачи:
---
Falcon хорош тем, что не навязывает структуру проекта: вы просто пишете классы-ресурсы и явно связываете их с маршрутами. Минимум магии — максимум контроля. Для небольшого, понятного REST API этого часто более чем достаточно.
Если Flask — это швейцарский нож, то Falcon — это скальпель. Минимум магии, максимум скорости и простоты. Он отлично подходит, когда нужно сделать легкий REST API без нагромождений.
---
## Установка
Falcon не входит в стандартную библиотеку, ставим:
pip install falcon
---
## Базовый пример: «Hello, API»
Создадим минимальный REST API, который отвечает JSON-ом.
import json
import falcon
class HelloResource:
def on_get(self, req, resp):
resp.status = falcon.HTTP_200
resp.media = {"message": "Hello, Falcon API!"}
app = falcon.App()
app.add_route("/hello", HelloResource())
Сохрани файл как
app.py, а запускать удобнее через uWSGI, gunicorn или waitress. Для разработки можно использовать falcon.App вместе с wsgiref:from wsgiref.simple_server import make_server
if __name__ == "__main__":
with make_server("127.0.0.1", 8000, app) as httpd:
httpd.serve_forever()
Переходим по
http://127.0.0.1:8000/hello и получаем JSON-ответ.---
## Обработка методов: GET и POST
Добавим ресурс для работы со списком задач. Хранить будем в памяти, как простой пример.
import falcon
tasks = []
class TasksResource:
def on_get(self, req, resp):
resp.media = {"tasks": tasks}
def on_post(self, req, resp):
data = req.media # Falcon сам распарсит JSON
title = data.get("title")
if not title:
resp.status = falcon.HTTP_400
resp.media = {"error": "title is required"}
return
task = {"id": len(tasks) + 1, "title": title}
tasks.append(task)
resp.status = falcon.HTTP_201
resp.media = task
app = falcon.App()
app.add_route("/tasks", TasksResource())
Теперь:
-
GET /tasks возвращает список задач,-
POST /tasks с JSON {"title": "Learn Falcon"} добавляет новую.---
## Обработка одного ресурса по ID
Добавим получение одной задачи:
class TaskItemResource:
def on_get(self, req, resp, task_id):
task_id = int(task_id)
for task in tasks:
if task["id"] == task_id:
resp.media = task
return
resp.status = falcon.HTTP_404
resp.media = {"error": "task not found"}
app = falcon.App()
app.add_route("/tasks", TasksResource())
app.add_route("/tasks/{task_id}", TaskItemResource())
---
Falcon хорош тем, что не навязывает структуру проекта: вы просто пишете классы-ресурсы и явно связываете их с маршрутами. Минимум магии — максимум контроля. Для небольшого, понятного REST API этого часто более чем достаточно.
👍5
Как использовать
---
## Базовое использование
Результат:
Важно:
---
## Создание словаря из двух списков
Классический приём:
Результат:
---
## Unpacking: оператор
Оператор
### Транспонирование “таблицы”
Представим матрицу как список строк:
Результат:
Мы как бы “повернули” таблицу: строки стали столбцами. Это один из самых элегантных трюков с
---
## Распаковка результата
Так можно “разобрать” список пар обратно на два отдельных набора данных.
---
## С
Иногда нужно и индекс, и значения из нескольких коллекций:
---
zip и unpacking в Python: собираем пазл из данныхzip — это маленькая функция, которая решает кучу рутинных задач: объединяет списки, разворачивает таблицы, помогает красиво перебирать данные. А в паре с распаковкой (unpacking, оператор *) она становится особенно мощной.---
## Базовое использование
zipzip “склеивает” несколько итерируемых объектов по позициям:names = ["Alice", "Bob", "Charlie"]
scores = [95, 82, 78]
for name, score in zip(names, scores):
print(name, "=>", score)
Результат:
Alice => 95
Bob => 82
Charlie => 78
Важно:
zip обрезает результат по самому короткому списку.---
## Создание словаря из двух списков
Классический приём:
keys = ["host", "port", "debug"]
values = ["localhost", 8000, True]
config = dict(zip(keys, values))
print(config)
Результат:
{'host': 'localhost', 'port': 8000, 'debug': True}
---
## Unpacking: оператор
* в действииОператор
* “распаковывает” итерируемые объекты. В связке с zip это особенно полезно.### Транспонирование “таблицы”
Представим матрицу как список строк:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
transposed = list(zip(*matrix))
print(transposed)
Результат:
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Мы как бы “повернули” таблицу: строки стали столбцами. Это один из самых элегантных трюков с
zip.---
## Распаковка результата
zipzip возвращает итератор, его тоже можно распаковать:pairs = list(zip(names, scores))
print(pairs) # [('Alice', 95), ('Bob', 82), ('Charlie', 78)]
unzipped_names, unzipped_scores = zip(*pairs)
print(unzipped_names) # ('Alice', 'Bob', 'Charlie')
print(unzipped_scores) # (95, 82, 78)
Так можно “разобрать” список пар обратно на два отдельных набора данных.
---
## С
enumerate и zip: удобный переборИногда нужно и индекс, и значения из нескольких коллекций:
for idx, (name, score) in enumerate(zip(names, scores), start=1):
print(f"{idx}. {name}: {score}")
---
zip и unpacking — это инструменты, которые делают код короче, читабельнее и “питоничнее”. Освоив их, вы начнёте мыслить данными как блоками, которые легко собирать и разбирать, словно конструктор.👍3🔥2
Python для начинающих: работа с очередями через модуль
Если вам когда‑нибудь приходилось организовывать задачи «по очереди», то модуль
### Зачем нужна очередь?
Очередь (FIFO — first in, first out) — структура, которая забирает элементы в том же порядке, в котором они были добавлены. Это удобно для:
- обработки задач по мере поступления;
- организации «конвейеров» (один поток кладёт, другой забирает);
- ограничения количества элементов (защита от переполнения памяти).
### Базовый пример:
Методы:
-
-
-
### Очередь в многопоточности
Здесь:
- один поток «производит» задачи;
- второй их «потребляет»;
-
### LIFO и приоритеты
Модуль
Стек (LIFO):
Очередь с приоритетом:
Элемент с наименьшим приоритетом (числом) будет обработан первым.
---
Модуль
queueЕсли вам когда‑нибудь приходилось организовывать задачи «по очереди», то модуль
queue — именно то, что нужно. Это стандартный модуль Python для безопасной работы с очередями в многопоточных программах. Но им удобно пользоваться и в обычных скриптах.### Зачем нужна очередь?
Очередь (FIFO — first in, first out) — структура, которая забирает элементы в том же порядке, в котором они были добавлены. Это удобно для:
- обработки задач по мере поступления;
- организации «конвейеров» (один поток кладёт, другой забирает);
- ограничения количества элементов (защита от переполнения памяти).
### Базовый пример:
Queuefrom queue import Queue
task_queue = Queue(maxsize=3) # ограничим размер
task_queue.put("task_1")
task_queue.put("task_2")
task_queue.put("task_3")
print(task_queue.full()) # True
item = task_queue.get()
print("Got:", item)
print("Empty:", task_queue.empty())
Методы:
-
put(item) — положить элемент (по умолчанию будет ждать, если очередь заполнена);-
get() — забрать элемент (будет ждать, если очередь пуста);-
full(), empty(), qsize() — состояние очереди.### Очередь в многопоточности
queue.Queue уже потокобезопасна: можно спокойно использовать ее в разных потоках без дополнительных блокировок.from queue import Queue
from threading import Thread
import time
task_queue = Queue()
def producer():
for i in range(5):
task = f"task_{i}"
print("Produce:", task)
task_queue.put(task)
time.sleep(0.2)
task_queue.put(None) # сигнал завершения
def consumer():
while True:
task = task_queue.get()
if task is None:
break
print("Consume:", task)
task_queue.task_done()
t1 = Thread(target=producer)
t2 = Thread(target=consumer)
t1.start()
t2.start()
t1.join()
t2.join()
Здесь:
- один поток «производит» задачи;
- второй их «потребляет»;
-
None — маркер завершения работы.### LIFO и приоритеты
Модуль
queue умеет не только обычные очереди.Стек (LIFO):
from queue import LifoQueue
stack = LifoQueue()
stack.put("first")
stack.put("second")
print(stack.get()) # second
print(stack.get()) # first
Очередь с приоритетом:
from queue import PriorityQueue
pq = PriorityQueue()
pq.put((2, "low"))
pq.put((1, "high"))
pq.put((3, "very_low"))
while not pq.empty():
priority, item = pq.get()
print(priority, item)
Элемент с наименьшим приоритетом (числом) будет обработан первым.
---
Модуль
queue — это простой способ навести порядок в задачах и безопасно разделить работу между потоками. Даже если вы пока не лезете в сложную многопоточность, привычка использовать очереди поможет вам строить более чистую и предсказуемую архитектуру программ.🔥4
Изучение структур данных: стек и очередь на Python
Если вы пишете код «как-нибудь в списки», рано или поздно всё превращается в хаос. Структуры данных — это способ договориться с самим собой, как именно вы пользуетесь коллекцией. Сегодня разберём две классики: стек и очередь.
---
### Стек: принцип «последним пришёл — первым ушёл» (LIFO)
Стек — как стопка тарелок: снимаем сверху, кладём тоже сверху.
В Python стек удобно реализовать обычным списком:
Где это полезно:
- отмена действий (undo),
- обход деревьев,
- проверка правильности скобок в строке.
Мини‑пример проверки скобок:
---
### Очередь: «первым пришёл — первым ушёл» (FIFO)
Очередь — как линия в супермаркете: обслуживают по порядку.
Наивный вариант через список:
Проблема:
---
### Когда что использовать
- Стек — когда важно вернуться назад: история браузера, рекурсивные алгоритмы, разбор выражений.
- Очередь — когда задачи должны обрабатываться по мере поступления: обработка запросов, планирование задач, очереди сообщений.
Понимание этих двух структур — фундамент для более сложных: деревьев, графов, очередей с приоритетами. И да, в Python почти всегда достаточно
Если вы пишете код «как-нибудь в списки», рано или поздно всё превращается в хаос. Структуры данных — это способ договориться с самим собой, как именно вы пользуетесь коллекцией. Сегодня разберём две классики: стек и очередь.
---
### Стек: принцип «последним пришёл — первым ушёл» (LIFO)
Стек — как стопка тарелок: снимаем сверху, кладём тоже сверху.
В Python стек удобно реализовать обычным списком:
stack = []
# push
stack.append(1)
stack.append(2)
stack.append(3)
print(stack) # [1, 2, 3]
# pop (снимаем с вершины)
top = stack.pop()
print(top) # 3
print(stack) # [1, 2]
# просмотр вершины без удаления
peek = stack[-1]
print(peek) # 2
Где это полезно:
- отмена действий (undo),
- обход деревьев,
- проверка правильности скобок в строке.
Мини‑пример проверки скобок:
def is_brackets_balanced(expr: str) -> bool:
stack = []
pairs = {')': '(', ']': '[', '}': '{'}
for ch in expr:
if ch in '([{':
stack.append(ch)
elif ch in ')]}':
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
print(is_brackets_balanced("(a[b]{c})")) # True
print(is_brackets_balanced("(a[b]{c}")) # False
---
### Очередь: «первым пришёл — первым ушёл» (FIFO)
Очередь — как линия в супермаркете: обслуживают по порядку.
Наивный вариант через список:
queue = []
queue.append("task1")
queue.append("task2")
queue.append("task3")
first = queue.pop(0) # медленно на больших данных
print(first) # task1
Проблема:
pop(0) сдвигает весь список, что дорого по времени. Для нормальной очереди используем collections.deque:from collections import deque
queue = deque()
queue.append("task1")
queue.append("task2")
queue.append("task3")
first = queue.popleft()
print(first) # task1
print(queue) # deque(['task2', 'task3'])
deque оптимизирован под быстрые операции с обоих концов.---
### Когда что использовать
- Стек — когда важно вернуться назад: история браузера, рекурсивные алгоритмы, разбор выражений.
- Очередь — когда задачи должны обрабатываться по мере поступления: обработка запросов, планирование задач, очереди сообщений.
Понимание этих двух структур — фундамент для более сложных: деревьев, графов, очередей с приоритетами. И да, в Python почти всегда достаточно
list и deque, вопрос только в том, как вы их используете.❤2👍1🔥1
Сериализация с помощью pickle: плюсы и минусы
В какой‑то момент каждый питонист приходит к вопросу: как сохранить объект «как есть», а потом просто загрузить и продолжить работу? Стандартный ответ в мире Python — модуль
---
### Что такое pickle?
То есть:
- сериализация — превращаем объект в байтовую строку;
- десериализация — восстанавливаем объект из байтов.
Простейший пример:
Выглядит идеально: один модуль, одна строка — и ваш словарь переезжает на диск.
---
### Сильные стороны pickle
1. Работает «из коробки» почти со всем
Списки, словари, множества, пользовательские классы, вложенные структуры —
2. Минимум кода и усилий
Нет нужды вручную описывать поля, типы и схемы.
3. Удобен для быстрых прототипов и кэшей
Например, можно сохранить обученную модель или результат тяжёлых вычислений:
---
### Обратная сторона: минусы и подводные камни
1. Опасность безопасности
Главное правило:
> Никогда не делайте
2. Формат специфичен для Python
Другие языки
3. Хрупкость к изменению кода
Измените структуру класса — старые
4. Бинарный и нечитаемый
Нельзя просто открыть файл в редакторе и «глазами» понять, что внутри.
---
### Когда использовать pickle, а когда — нет?
Подходит:
- временные кэши;
- быстрые прототипы;
- сохранение внутренних объектов между запусками скрипта;
- сценарии, где и сохраняет, и загружает один и тот же контролируемый код.
Лучше избегать:
- всё, что связано с внешними пользователями;
- публичные API и сетевые протоколы;
- долгосрочное хранение важных данных;
- ситуации, где нужен человекочитаемый формат.
---
В какой‑то момент каждый питонист приходит к вопросу: как сохранить объект «как есть», а потом просто загрузить и продолжить работу? Стандартный ответ в мире Python — модуль
pickle. Он умеет превращать почти любые объекты в байты и обратно. Но у этой магии есть цена.---
### Что такое pickle?
pickle — это бинарный формат сериализации Python‑объектов. То есть:
- сериализация — превращаем объект в байтовую строку;
- десериализация — восстанавливаем объект из байтов.
Простейший пример:
import pickle
data = {"user": "alice", "score": 42, "tags": ["python", "pickle"]}
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
with open("data.pkl", "rb") as f:
loaded = pickle.load(f)
print(loaded)
Выглядит идеально: один модуль, одна строка — и ваш словарь переезжает на диск.
---
### Сильные стороны pickle
1. Работает «из коробки» почти со всем
Списки, словари, множества, пользовательские классы, вложенные структуры —
pickle справится.2. Минимум кода и усилий
Нет нужды вручную описывать поля, типы и схемы.
3. Удобен для быстрых прототипов и кэшей
Например, можно сохранить обученную модель или результат тяжёлых вычислений:
import pickle
class Model:
def __init__(self, weights):
self.weights = weights
model = Model(weights=[0.1, 0.5, 0.9])
with open("model.pkl", "wb") as f:
pickle.dump(model, f)
# ... позже
with open("model.pkl", "rb") as f:
restored_model = pickle.load(f)
---
### Обратная сторона: минусы и подводные камни
1. Опасность безопасности
Главное правило:
> Никогда не делайте
pickle.load() на данных из непроверенного источника.pickle может при десериализации выполнять произвольный код. Это не баг, а особенность протокола.2. Формат специфичен для Python
Другие языки
pickle не понимают. Обмениваться данными с внешними сервисами удобнее через JSON, Protobuf и т.п.3. Хрупкость к изменению кода
Измените структуру класса — старые
.pkl могут перестать корректно загружаться. Для долгосрочного хранения это риск.4. Бинарный и нечитаемый
Нельзя просто открыть файл в редакторе и «глазами» понять, что внутри.
---
### Когда использовать pickle, а когда — нет?
Подходит:
- временные кэши;
- быстрые прототипы;
- сохранение внутренних объектов между запусками скрипта;
- сценарии, где и сохраняет, и загружает один и тот же контролируемый код.
Лучше избегать:
- всё, что связано с внешними пользователями;
- публичные API и сетевые протоколы;
- долгосрочное хранение важных данных;
- ситуации, где нужен человекочитаемый формат.
---
pickle — это мощный, но «острый» инструмент. Для внутренних задач разработчика он экономит часы работы. Для обмена данными и публичных сервисов чаще всего безопаснее и разумнее выбрать более строгие и переносимые форматы.👍2🔥2
Создаём свой первый 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