Невозможно использовать декоратор для дочернего класса, наследуемого от родительского класса, но можно использовать его для самого объекта

Я создаю класс, наследуемый от родительского класса. Родительский класс — это Telebot, а дочерний класс — это мой собственный класс Telegram BOT. Я делаю это, чтобы создать стандартный BOT, который будет вызываться и реализовываться несколькими сценариями с действиями по умолчанию и т. д.

Затем я пытаюсь реализовать декоратор для обработки входящих сообщений по умолчанию в этом дочернем классе. Вот как я это делаю (файл telegram.py):

# Importo a biblioteca que vou usar pra criar meu BOT
import telebot


class TelegramBot(telebot.TeleBot):
    """
    Essa classe é chamada para criar uma instância de um BOT do Telegram.
    Ela herda a classe Telebot do módulo telebot.
    Doc: https://pytba.readthedocs.io/en/latest/sync_version
    """

    def __init__(self, token):
        """Esta função é chamada no momento que a classe é instanciada.
        Herda os atributos do telebot"""

        super().__init__(token)

    def polling(self):
        """Este método está sendo incrementado com algumas funcionalidades
        próprias do bot, ao invés de ser feito o override/polimorfismo."""
        super().polling()

    @telebot.TeleBot.message_handler(commands=["testar_bot"])
    def resposta_teste(self, mensagem):
        """Esse método utiliza do Decorator para ter uma nova caracteristica e funcionalidade,
         que define o padrão para cada mensagem recebida.
         O método testa a resposta padrão para fazer o teste no BOT.
         """

        self.reply_to(mensagem, "Olá! Teste passou. Tudo funcionando :)")

Делая это так, я получаю сообщение об ошибке: TypeError: TeleBot.message_handler() missing 1 required positional argument: 'self'

Самое странное, что если я удалю декоратор вместе с методом и реализую его в моем объекте бота в моем файле main.py, он будет работать как шарм.

Вот код, который работает — я удаляю декоратор из класса и ставлю его main.py:


import telegram

bot = telegram.TelegramBot("blablabla_mytokenhidden")


@bot.message_handler(commands=["testar_bot"])
def resposta_teste(mensagem):
    """Esse método utiliza do Decorator para ter uma nova caracteristica e funcionalidade,
     que define o padrão para cada mensagem recebida.
     O método testa a resposta padrão para fazer o teste no BOT.
     """

    bot.reply_to(mensagem, "Olá! Teste passou. Tudo funcionando :)")


bot.polling()

Это не дает мне никаких ошибок, и декоратор работает как шарм. Я действительно не понимаю логики этого.

Почему декоратор, который я использовал для своего объекта, работает, а для моего дочернего класса (telegram.py с классом TelegramBot) — нет?

Изменить №1

Следуя логике объекта, я попытался заменить telebot.TeleBot на self, также проверил с object, и это все равно не сработало...

Так что я явно НЕ понимаю логику здесь.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Метод, определенный в классе, требует, чтобы экземпляр класса передавался в качестве первого аргумента (self) при его вызове. (Это делается для вас, когда вы вызываете его с помощью записи через точку, т.е. instance.method().) Декоратор @telebot.TeleBot.message_handler() вызывается во время определения класса, до того, как появятся какие-либо экземпляры. Поэтому обработчик не знает, к какому экземпляру он подключен, поэтому он хочет, чтобы вы передали self в себя. На что, конечно же, бот-фреймворк не настроен.

Естественно, это не проблема, когда обработчик определен вне класса, потому что он не требует экземпляра класса, к которому он присоединен, не привязан к классу и все такое.

Одним из решений является применение декоратора при создании экземпляра:

def __init__(self, token):
        """Esta função é chamada no momento que a classe é instanciada.
        Herda os atributos do telebot"""

        super().__init__(token)
        self.resposta_teste = telebot.TeleBot.message_handler(
            commands=["testar_bot"])(self. resposta_teste)

Это делает обработчик связанным методом своего экземпляра с уже запеченным self. Обратите внимание, что это может вызвать проблемы, если вы создадите несколько экземпляров класса, поскольку к одному и тому же событию будет прикреплено несколько обработчиков. Фреймворк, который вы используете, может быть в порядке с этим, а может и нет.

Еще одна вещь, которую вы можете сделать, если у вас не будет нескольких экземпляров бота (или если обработчику не нужно знать, к какому экземпляру он подключен), — это сделать метод статическим. Затем она ведет себя как обычная функция (хотя и в пространстве имен класса) и не нуждается в передаче экземпляра.

class TelegramBot(telebot.TeleBot):

    # ...

    @telebot.TeleBot.message_handler(commands=["testar_bot"])
    @staticmethod
    def resposta_teste(mensagem):
        """Esse método utiliza do Decorator para ter uma nova caracteristica e funcionalidade,
         que define o padrão para cada mensagem recebida.
         O método testa a resposta padrão para fazer o teste no BOT.
         """

        self.reply_to(mensagem, "Olá! Teste passou. Tudo funcionando :)")

Я читаю, что такое декораторы и как они работают... Довольно аккуратно, но сложно. Хорошо. Оба ваших решения сработали и помогли мне немного лучше понять эту концепцию. Спасибо @kindall!

Raul Chiarella 09.02.2023 21:55

Декораторы — это круто, но вам нужно, чтобы сами функции были значениями, которые вы можете просто передавать, как строки или числа. Декоратор — это просто функция, которая принимает функцию и возвращает функцию, со специальным синтаксисом для ее вызова в точке определения функции. (Или класс. Вы можете написать декоратор, который украшает класс, и сам декоратор может быть классом.)

kindall 09.02.2023 22:10

Другие вопросы по теме