Принцип регистрации хендлеров
LatandСейчас мы кратко рассмотрим как работает принцип регистрации хендлеров и доставки апдейтов до наших функций-обработчиков.
Содержание статьи
├── Порядок регистрации хендлеров ├── Доставка апдейта до нужного хендлера ├── Движение объекта Dispatcher по модулям
Порядок регистрации хендлеров
Предположим у нас есть такой хендлер:
Что же тут делает декоратор message_handler?
Открываем источник и видим такое:
Декоратор вызывает функцию register_message_handler и передает в нее все условия (фильтры), что мы указали и callback (функцию, в которой мы хотим обрабатывать наше сообщение).
А что же происходит в функции register_message_handler?
Тут регистрируются наши условия (фильтры) и выполняется метод register у объекта message_handlers. То есть, если мы возьмем вместо декоратора просто функцию dp.register_message_handler - будет тот же результат, что и декоратором.
Давайте разберемся, что же это за функция register?
Есть некий класс Handler, у которого есть атрибут-список хендлеров, называется он self.handlers
И выполняя функцию register, мы добавляем наш HandlerObj, в котором будет нужная нам функция с нужными фильтрами, в список хендлеров этого типа (например message или callback_query).
Доставка апдейта до нужного хендлера
Если посмотреть в объект Dispatcher, то увидим следующее:
У диспатчера есть набор атрибутов-хендлеров. Это и message_handlers, и edited_message_handlers и channel_post_handlers и другие. Это те самые объекты типа Handler, у которого есть список self.handlers, в который мы добавляем наши обработчики.
Теперь, когда нам понятно как регистрируются наши хендлеры, давайте глянем, что происходит, когда приходит апдейт.
У Dispatcher есть метод process_update, который проверяет тип апдейта, и выполняет функцию notify у нужного типа хендлеров.
Заходим в метод notify и видим:
- Если на типа хендлеров установлен ключ миддлваря, то тригеррится функция pre_process_ у необходимого типа апдейтов. Подробнее про миддлвари тут.
- Происходит итерация по ЗАРЕГИСТРИРОВАННЫМ хендлерам этого типа (например message). Тот самый список, в который делали append в объекте Handler.
- Идет проверка на фильтры в каждом хендлере. Если все условия не выполняются - поднимается ошибка FilterNotPassed, и в этой строке она обрабатывается и происходит переход к следующему хендлеру.
- Теперь, когда ошибка не случилась- фильтры подошли, триггерится уже миддлварь ключа process_
- После чего выполняется та функция, которую мы зарегистрировали с нужными параметрами (переданными, как самим аиограмом, так и через миддлвари).
Движение объекта Dispatcher по модулям
Теперь, собственно, как я регистрирую хендлеры в проекте, где много разных модулей.
- В одном модуле (loader.py) инициализируются важные для работы переменные - bot, dispatcher. Их я импортирую в модулях хендлеров и с помощью декоратора добавляю в dp.message_handlers (например) мои функции.
- Каждый раз когда я делаю импорт dp из модуля хендлеров - Python понимает, что я использую тот же самый объект dp из файла loader.py и просто пишет на него же новые хендлеры из других модулей моего проекта.
- После чего, готовый объект диспатчера, со всеми навешенными на него хендлерами, передается в модуль app.py, где и происходит запуск бота .
Графическую схему работы можно посмотреть в посте тут.