Сторонние декораторы в классе. ООП
Вопрос. Почему этот код воспроизводится так как надо хотя вызова самого класса нет. Есть предположение что из-за того что была вызвана переменная dp, но на сколько это достоверно мне не понятно и на сколько практично.
from aiogram import Bot, Dispatcher, executor, types
import config
bot = Bot(token=config.TOKEN_TESTING, parse_mode=types.ParseMode.MARKDOWN_V2)
dp = Dispatcher(bot)
class SheduleBot:
@dp.message_handler(commands=['today' ])
async def queue(message):
await message.reply("```\nОтправь мне в личку сообщение```\n")
#shedule_bot = SheduleBot()
executor.start_polling(dp, skip_updates=True)
Ответы (2 шт):
Декораторы - это обертка, позволяющая сделать что то до функции или после, в вашем случае вызывается этот декоратор, который регистриует вDispatcher-e(dp) ваш обработчик сообщений и в ответ на сообщения пользователя уже использует его
Почему этот код воспроизводится так как надо хотя вызова самого класса нет.
Класс как раз есть, это объекта нет.
Почему срабатывают декораторы - потому что всё внутри класса (кроме содержимого методов) выполняется сразу при загрузке модуля (тупо, если print внутрь класса вставить снаружи методов, он сработает при старте). Поэтому и методы создаются, и выполняются декораторы. А дальше через диспетчер просто вызываются методы, зарегистрированные декораторами.
Демонстрационный код, без асинхронности, но суть та же самая:
from collections import defaultdict
from typing import List
class Dispatcher:
def __init__(self):
self.functions = defaultdict(list)
def message_hanlder(self, commands: List[str]):
print("Внутри message_hanlder, commands =", commands)
def decorator(func):
print("Внутри декоратора на функции", func)
# В данном случае декоратор ничем не оборачивает функцию
# а просто регистрирует ее как обработчик команд
# и возвращает ее же саму, а не wrapper
for command in commands:
self.functions[command].append(func)
return func
print("Выходим из message_hanlder")
return decorator
def send_message(self, command: str, message: str):
for func in self.functions[command]:
func(message)
dp = Dispatcher()
class SomeClass:
print("Внутри класса SomeClass")
@dp.message_hanlder(commands=["yesterday", "today"])
def handler1(message):
print("Handler1:", message)
print("Между методами класса SomeClass")
@dp.message_hanlder(commands=["today", "tomorrow"])
def handler2(message):
print("Handler2:", message)
print("Посылаем сообщения")
dp.send_message(command="yesterday", message="Hello!")
dp.send_message(command="today", message="Bye!")
dp.send_message(command="tomorrow", message="Hello again!")
Вывод:
Внутри класса SomeClass
Внутри message_hanlder, commands = ['yesterday', 'today']
Выходим из message_hanlder
Внутри декоратора на функции <function SomeClass.handler1 at 0x7fb610b3c1f0>
Между методами класса SomeClass
Внутри message_hanlder, commands = ['today', 'tomorrow']
Выходим из message_hanlder
Внутри декоратора на функции <function SomeClass.handler2 at 0x7fb610b3c280>
Посылаем сообщения
Handler1: Hello!
Handler1: Bye!
Handler2: Bye!
Handler2: Hello again!
Т.е. видно, что и print внутри класса сразу отработал, и декораторы выполнились сразу при старте.
Еще очевиднее будет, если вспомнить, что декоратор - это просто функция, в которую передается декорируемая функция, и возвращается другая функция (или та же самая в данном случае, но декорируемая функция регистрируется диспетчером). Поэтому класс можно переписать так:
class SomeClass:
print("Внутри класса SomeClass")
def handler1(message):
print("Handler1:", message)
handler1 = dp.message_hanlder(commands=["yesterday", "today"])(handler1)
print("Между методами класса SomeClass")
def handler2(message):
print("Handler2:", message)
handler2 = dp.message_hanlder(commands=["today", "tomorrow"])(handler2)
При этом все будет работать точно так же.
То, что декоратор является методом объекта dp, никак на результат не влияет, точно такое же поведение будет и если декоратор будет отдельной функцией.