@Ninzalo

Как инициализировать декоратор в классе, а внутри использовать этот декоратор?

есть такой файлик:
Код

from aiogram import asyncio, types, executor
from lib.bot.struct import Message_struct
from lib.bot.converters import str_to_dict
from lib.server import send_to_server

# Ensure to import config for tg
from lib.bot.messengers_configs.tg_config import dp


@dp.callback_query_handler()
async def inline_kb_answer_callback_handler(
    query: types.CallbackQuery,
) -> None:
    message_struct = Message_struct(
        user_id=query.from_user.id,
        messenger="tg",
        payload=str_to_dict(string=query.data),
    )
    await send_to_server(message=message_struct)


@dp.message_handler()
async def echo_handler(message: types.Message) -> None:
    message_struct = Message_struct(
        user_id=message.from_id, messenger="tg", text=message.text
    )
    await send_to_server(message=message_struct)

def start_tg_client() -> None:
    print(f"TG listening started")
    executor.start_polling(dp, skip_updates=True)


if __name__ == "__main__":
    start_tg_client()


Появилась задача обернуть весь этот функционал в класс и вызывать его в другом месте. При этом Dispatcher я настраиваю в другом файле и импортирую в этот
Хотелось бы узнать, возможно ли на моменте инициализации класса определять декоратор @dp?
Попытки

from aiogram import asyncio, types, executor
from lib.bot.struct import Message_struct
from lib.bot.converters import str_to_dict
from lib.server import send_to_server

class Tg_client:
    def __init__(self, dp) -> None:
        self._dp = dp

    @self._dp.callback_query_handler()
    async def inline_kb_answer_callback_handler(
        query: types.CallbackQuery,
    ) -> None:
        message_struct = Message_struct(
            user_id=query.from_user.id,
            messenger="tg",
            payload=str_to_dict(string=query.data),
        )
        await send_to_server(message=message_struct)


    @self._dp.message_handler()
    async def echo_handler(message: types.Message) -> None:
        message_struct = Message_struct(
            user_id=message.from_id, messenger="tg", text=message.text
        )
        await send_to_server(message=message_struct)


    def start_tg_client() -> None:
        print(f"TG listening started")
        executor.start_polling(self._dp, skip_updates=True)

if __name__ == "__main__":
    from lib.bot.messengers_configs.tg_config import dp
    tg_client = Tg_client(dp=dp)
    tg_client.start_tg_client()

Сделать не получается, так как при инициализации класс не знает что это за декоратор - @dp, также как и о параметрах self
Есть ли способ это обойти?

UPD:
Попытка, которая работает, но, возможно, требует улучшений

from aiogram import types, executor
from lib.bot.struct import Message_struct
from lib.bot.converters import str_to_dict
from lib.server import send_to_server


class Tg_client:
    def __init__(self, dp) -> None:
        self._dp = dp
        self._dp.callback_query_handler()(
            self.inline_kb_answer_callback_handler
        )
        self._dp.message_handler()(self.echo_handler)

    async def inline_kb_answer_callback_handler(
        self,
        query: types.CallbackQuery,
    ) -> None:
        message_struct = Message_struct(
            user_id=query.from_user.id,
            messenger="tg",
            payload=str_to_dict(string=query.data),
        )
        await send_to_server(message=message_struct)

    async def echo_handler(self, message: types.Message) -> None:
        message_struct = Message_struct(
            user_id=message.from_id, messenger="tg", text=message.text
        )
        await send_to_server(message=message_struct)

    def start_tg_client(self) -> None:
        print(f"TG listening started")
        executor.start_polling(self._dp, skip_updates=True)


if __name__ == "__main__":
    from lib.bot.messengers_configs.tg_config import dp
    tg_client = Tg_client(dp=dp)
    tg_client.start_tg_client()

  • Вопрос задан
  • 186 просмотров
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Ты хочешь поместить хэндлеры в класс?
Я в таких случаях делаю немного иначе.
Делаю свой декоратор, который принимает те же параметры, что и ботовый, но просто сохраняет их в отдельном атрибуте декорируемого метода. Благо методу можно создать новый атрибут через setattr() или простым присваиванием.
При конструировании экземпляра класса через dir() перечисляю содержимое класса, ищу методы, среди них ищу методы с моим атрибутом (т.е. те, которые были декорированы). Для каждого такого метода получаю bound method (через getattr(self, method_name)) и вызываю оригинальный декоратор на нём с сохранёнными параметрами. Ведь декоратор - это функция, его можно вызывать как функцию.
Часть, связанную с конструированием, можно спрятать или в родительском абстрактном классе, или в метаклассе, чтобы не повторять для каждого класса с обработчиками.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы