Почему не работает несколько событий on_message? - PullRequest
0 голосов
/ 04 мая 2018

Почему я не могу иметь несколько on_message событий?

import discord

client = discord.Client()

@client.event
async def on_ready():
    print('in on_ready')

@client.event
async def on_message(message):
    print("in on_message #1")

@client.event
async def on_message(message):
    print("in on_message #2")

@client.event
async def on_message(message):
    print("in on_message #3")

client.run("TOKEN")

Например, если я что-то набрал с разногласия, всегда срабатывает только последний on_message. Как я могу заставить всех троих работать?

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

В питоне функции - это просто объекты.

>>> def foo():
...     print ("hi")

определяет объект с именем foo. Это можно увидеть с помощью оболочки Python.

>>> foo
<function foo at 0x...>
>>> foo()
hi

Если вы определите новый метод после или переопределите переменную foo, вы потеряете доступ к исходной функции.

>>> foo = "hi"
>>> foo
hi
>>> foo()
Traceback ...:
    file "<stdin>" ...
TypeError: 'str' object is not callable

Как работает декоратор @client.event, он сообщает вашему клиенту, что новые сообщения должны передаваться в сообщения, и, если метод переопределен, это означает, что старый метод потерян.

>>> @bot.event
... async def on_message(m):
...     print(1)
...
>>> bot.on_message(None) # @bot.event makes the bot define it's own method
1
>>> @bot.event
... async def on_message(m):
...     print(2)
...
>>> bot.on_message(None) # bot's own method was redefined.
2
0 голосов
/ 04 мая 2018

Это невозможно с нативным Client

Вы можете иметь только one on_message, если у вас есть несколько, только последний будет вызван для события on_message. Вам просто нужно объединить свои три on_message.

import discord

client = discord.Client()

@client.event
async def on_message(message):
    print("in on_message #1")
    print("in on_message #2")
    print("in on_message #3")

client.run("TOKEN")

Как и любая переменная / функция Python (если декоратор не хранит вашу функцию, @client.event делает это, сохраняя только самый последний обратный вызов), если несколько имен совпадают, самое последнее будет сохранено, а все остальные получат перезаписаны.

Это простой пример, который я написал, чтобы дать вам общее представление о том, как работают события в discord.py (примечание: реальный код не совсем такой, так как он переписан и значительно сокращен).

class Client:
    def event(self, func):               
        if func.__name__ == "on_message":
            self.on_message_handle = func
            return func

    def receive_message(self, msg):
        func = getattr(self, "on_message_handle", None)
        if func is not None:
            func(msg)
        else:
            self.process_commands(msg)

client = Client()

@client.event
def on_message(msg):
    print("in on_message #1")

@client.event
def on_message(msg):
    print("in on_message #2")

client.receive_message("hello")
# "in on_message #2"

Как видите, client.event хранит только один экземпляр on_message.


Вы можете с Bot экземплярами

В качестве альтернативы, если вы используете расширение ext.commands для discord.py, существует собственный способ иметь несколько on_message обратных вызовов. Вы делаете это, используя определение их как listener. Вы можете иметь не более одного on_message события и неограниченное количество on_message слушателей.

from discord.ext import commands

bot = commands.Bot('.')

@bot.event
async def on_message(msg):
    print("in on_message #1")
    await bot.process_commands(msg)  # so `Command` instances will still get called


@bot.listen()
async def on_message(msg):
    print("in on_message #2")


@bot.listen()
async def on_message(msg):
    print("in on_message #3")

bot.run("TOKEN")

При получении сообщения все on_message #1-3 будут распечатаны.

...