はじめに
discord.pyでext.commandsフレームワークを使い始めたときに、Cogを使おうと思っても、うまくいかない人が多いです。そんな人のために、解説をしていきたいと思います。
追記: discord.py 2.0aの、extension/cogの読み込みが非同期になるというアップデートに対応しました。
Cogとは?
Cogの解説にも書いてありますが、Bot開発においてコマンドやリスナー、いくつかの状態を一つのクラスにまとめるために作られました。
例えば、コマンドのカテゴリーごとの分類や、リスナーを機能ごとに切り分けたようなものです。オブジェクト指向ですね。
Cogはcommands.Cogを継承したクラスを作れば作ることが可能です。
こんな感じ:
from discord.ext import commands
class MyCog(commands.Cog):
pass
Cogの中でコマンドを作る
Cogの中でコマンドを作るためには、ちょっと違う方法を使います。
普通botでコマンドを作るときは、@bot.command()
を使いますが、Cogの中で作るときは@commands.command()
を使います。
こんな感じ:
from discord.ext import commands
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
async def cat(self, ctx):
await ctx.send('にゃーん?')
@commands.command()
async def dog(self, ctx):
await ctx.send('わん!')
Cogの中でイベントリスナーを使う
Cogの中で@bot.event
のようにイベントを取得したい場合は、@commands.Cog.listener()
を使用します。
このlistenerにはname引数があり、これを使うことでどんな名前の関数でもリスナーにできます!
また、全てのリスナーが独立しているので、いくらでも作ることが可能です。
こんな感じ:
from discord.ext import commands
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener(name='on_message')
async def good_reaction(self, message):
if message.author.bot:
return
if 'いいね' in message.content:
await message.add_reaction('\U0001f44d')
__init__にbot引数つけてること多いけど何?
例えばbotにある関数、例えばbot.reload_extension
などを使いたいとき、Botのインスタンスを参照する必要があります。なので、__init__
するときに渡すことで、後から参照できるということです。
Extensionとは?
Extensionの解説にもありますが、ホットリロードを簡単に行えるようにするための機能です。これがあることで、Botを落とさないでコマンドを変更可能です。
Extensionはload/reload/unloadが可能です。
**Extensionのファイルにはsetup関数が必要です。**このsetup関数は、Extensionがloadされたときに必ず呼び出されます。
逆に、unloadされたときにはteardown関数が呼び出されます。
例えば:
async def setup(bot):
print('ロードされました')
とだけ書いたファイルを読み込めば、それだけでExtensionを使うことができます。
Extensionの例はこちら
CogとExtensionの合わせ技
世の中にあるCogは、例えば:
from cogfile import MyCog
from discord.ext import commands
bot = commands.Bot()
...
await bot.add_cog(MyCog(bot))
とすることでロードできますが、Cogの中身を変えたときにBotを落とさずリロードしたいことがあります。そんなとき、CogとExtensionの合わせ技を使うと、超絶簡単にかけるのです!:
from discord.ext import commands
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener(name='on_message')
async def good_reaction(self, message):
if message.author.bot:
return
if 'いいね' in message.content:
await message.add_reaction('\U0001f44d')
# これが重要
async def setup(bot):
await bot.add_cog(MyCog(bot))
こうして
# from cogfile import MyCog
from discord.ext import commands
bot = commands.Bot()
# bot.add_cog(MyCog(bot))
...
await bot.load_extension('cogfile')
とすることで、ホットリロードができる形でロードできます!
注意
世の中にあるCogは8割ほどがCogとExtensionを両方使用しているものですが、それを写したときにsetup関数を忘れエラーになる人が多いです。setup関数は必須です。
また、CogとExtensionは別物です!同じものと勘違いをされている方がいるので、是非教えてあげてください。
さいごに
CogやExtensionでこういう説明/解説が欲しい!という方は、是非コメントにお書きください。