A few days ago I became interested in programming discord bots a bit. In the syntax of these programs I noticed a lot of unintelligible issues that I can not find an answer to.
That's why I am asking you for help in understanding them.
All questions are based on this code:
import discord
import asyncio
from discord.ext import commandsbotToken = '***'client = commands.Bot(command_prefix = '.')@client.event
async def on_ready():print('Bot is ready!')@client.event
async def on_message(message):author = message.authorif message.content =='Hello':await client.send_message(message.channel, 'Welcome again {}!'.format(author))client.run(botToken)
What is @client.event? I found that is a event handler, but how is it worki? Why is it needed to run program? Is it somehow connected to a asyncio?
When a Client
receives an event from Discord, It works out what that event is and generates, or locates, the objects that were sent by the event, such as a discord.Message
for any MESSAGE_RECEIVE events, or a discord.Reaction
for REACTION_ADD etc.
The client then sends the objects into the method that handles those events, but you first need to tell the client what those methods are. This is where the event decorators come in.
Decorators are, in essence, functions that take other functions as arguments. The most common one you'll see is @property
. This says that the function you define should be passed into the property()
function
@property
def name(self):return self._name
is the same as
def name(self):return self._namename = property(name)
This may be a bit confusing to wrap your head around, but this is how discord.py handles its events.
When you use the @client.event
decorator on your on_message
, what you are actually doing is saying on_message = client.event(on_message)
The internal code of discord.py for on_event is this
def event(self, coro):# Validation we don't need to worry aboutsetattr(self, coro.__name__, coro)return coro
Which means that it takes the function as its parameter, and sets a new attribute on the client itself. For our on_message
example, we pass our on_message
function into client.event()
and it makes the client define a new client.on_message
method that is the same method as our on_message
.
Note: func.__name__
returns the name of that function. on_message.__name__
will return "on_message"
.
setattr(obj, name, value)
sets an attribute on an object, so setattr(self, "foo", 100)
means that self.foo
will be 100.
Now that the client knows our on_message
, when it receives an event saying that a message was sent, it creates the discord.Message
object and passes that into client.on_message
, which as we already established, is the same as our own on_message
If you wanted, you could even just skip the decorator and do this after your function, but it is less elegant than a decorator is:
on_message = client.event(on_message)