ch
Feedback
Python для начинающих

Python для начинающих

前往频道在 Telegram

Python для начинающих

显示更多
1 240
订阅者
无数据24 小时
+17
+130
帖子存档
Создание прогресс-бара в терминале с использованием tqdm
Создание прогресс-бара в терминале с использованием tqdm

Парсинг командной строки с помощью getopt и argparse Когда скрипт перестаёт быть «одноразовым файлом» и превращается в инструмент, ему срочно нужны параметры командной строки. Флаги вроде --input data.csv или -v делают ваш код удобным, автоматизируемым и… чуть менее хаотичным. В Python для этого исторически есть два модуля: «олдскульный» getopt и современный, почти стандарт де-факто — argparse. --- ## getopt: минимализм в стиле POSIX getopt напоминает классический 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() и захардкоженными путями.

Парсинг командной строки с помощью модулей getopt и argparse
Парсинг командной строки с помощью модулей getopt и argparse

Как работать с цветом в терминале: библиотека 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 в свои маленькие утилиты: подсветите ошибки, выделите успешные шаги, сделайте прогресс более наглядным. Цвет в консоли — это простой инструмент, который заметно повышает удобство работы с программой.

Как работать с цветом в терминале: библиотека colorama
Как работать с цветом в терминале: библиотека colorama

Инструменты отладки кода: знакомство с модулем 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 — это минимальный, но мощный инструмент, который стоит освоить как можно раньше. Он дисциплинирует мышление: вместо хаотичных принтов вы начинаете осознанно исследовать состояние программы и понимать, почему она ведет себя так, а не иначе.

Инструменты отладки кода: использование модуля pdb
Инструменты отладки кода: использование модуля pdb

Изучение модуля 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, а когда нет sche­d хорош для: - простого планирования задач в одном потоке; - тестов и симуляций событий во времени; - ситуаций, где нужен контроль над порядком выполнения и временем. Если нужно: - сложное расписание (крон-подобное); - работа с разными часовыми поясами, датами, календарями; - продвинутая асинхронность, то лучше посмотреть в сторону APScheduler, asyncio или системного cron. Но для понимания базовых принципов планирования задач во времени sched — идеальный старт, да еще и без сторонних библиотек.

Изучение модуля sched: планирование задач во времени
Изучение модуля sched: планирование задач во времени

Работа с форматом YAML в Python с использованием PyYAML 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. Если вы часто имеете дело с настройками и инфраструктурой — эта библиотека станет обязательным пунктом в вашем наборе инструментов.

Работа с форматом YAML в Python с использованием PyYAML
Работа с форматом YAML в Python с использованием PyYAML

Python для начинающих: как подружиться с постраничной загрузкой из 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 тысячи и миллионы записей, не утонув ни в ошибках, ни в лимитах.

Как работать с постраничной загрузкой данных из API
Как работать с постраничной загрузкой данных из API

Создаём свой первый CLI-инструмент с argparse Рано или поздно каждый питонист приходит к мысли: «Хочу свою консольную утилиту!» Что‑нибудь, что запускается из терминала, принимает аргументы и делает полезное дело. В 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, а ощущение уже как от «настоящей» утилиты. Попробуйте переписать свой следующий скрипт так, чтобы он принимал аргументы командной строки — разница в удобстве будет огромной.

Создание простого cli-инструмента с аргументами через argparse
Создание простого cli-инструмента с аргументами через argparse

Сериализация с помощью pickle: плюсы и минусы В какой‑то момент каждый питонист приходит к вопросу: как сохранить объект «как есть», а потом просто загрузить и продолжить работу? Стандартный ответ в мире 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 — это мощный, но «острый» инструмент. Для внутренних задач разработчика он экономит часы работы. Для обмена данными и публичных сервисов чаще всего безопаснее и разумнее выбрать более строгие и переносимые форматы.

Сериализация с помощью модуля pickle: плюсы и минусы
Сериализация с помощью модуля pickle: плюсы и минусы

Изучение структур данных: стек и очередь на 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, вопрос только в том, как вы их используете.

Изучение структур данных: стек и очередь на Python
Изучение структур данных: стек и очередь на Python

Python для начинающих: работа с очередями через модуль queue Если вам когда‑нибудь приходилось организовывать задачи «по очереди», то модуль queue — именно то, что нужно. Это стандартный модуль Python для безопасной работы с очередями в многопоточных программах. Но им удобно пользоваться и в обычных скриптах. ### Зачем нужна очередь? Очередь (FIFO — first in, first out) — структура, которая забирает элементы в том же порядке, в котором они были добавлены. Это удобно для: - обработки задач по мере поступления; - организации «конвейеров» (один поток кладёт, другой забирает); - ограничения количества элементов (защита от переполнения памяти). ### Базовый пример: Queue
from 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 — это простой способ навести порядок в задачах и безопасно разделить работу между потоками. Даже если вы пока не лезете в сложную многопоточность, привычка использовать очереди поможет вам строить более чистую и предсказуемую архитектуру программ.