注意
既にアナウンスされている通り、discord.pyは2021年8月下旬ころ、以降のサポートを停止する旨発表されております。
もし本記事を参考にして不具合が生じた場合、ライブラリのサポート終了による影響である可能性もあります。
詳しくは the_future_of_dpy.md をご覧ください。
前提
- discord.py 1.3.0
- python 3.6
注意
この記事に出てくるコードは説明用に記載しているため、実運用を想定したものではありません。
用途に合わせて適切に書き換えてくださいね。
やりたいこと
Task
に引数を渡したい
なぜやりたいか
基本的に定期実行するTaskはbotの起動時に開始することが多いと思う。
ただ、時には、コマンドなどで開始タイミングや送信先チャンネルなどを制御したいことがある。
例えば、 「今から30分間だけ5分ごとに指定のチャンネルで時報をメンションしてほしい」 みたいな。
ところが、現状discord.pyのドキュメント内には、Task (https://discordpy.readthedocs.io/ja/latest/ext/tasks/index.html) が引数をとるような例がない。
方法
まずは、定期実行したいTaskに普通に引数を追加しておく。
例えば上記を例にして、コマンドが入力されたチャンネル内でコマンドを送信した人にメンションを送る場合を考える。
この場合だと、コマンド入力時のContext
を引数として受け取っておけば、チャンネルも送信者も特定できそうだ。
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self):
pass
def cog_unload(self):
self.reminder.cancel()
@tasks.loop(minutes=5.0, count=6)
async def reminder(self, ctx, content):
await ctx.send("<@{0}> {1}".format(ctx.author.id, content))
こんな感じでreminderを定義しておけば、後はこれを起動すればいい感じにリマインドが飛んでくれるだろう。
では、この引数ctx
を渡すにはどうすればよいか。
Taskの引数はstart()に渡す
タイトル通り。task開始時に使うstart()
に渡せばよい。start()
に渡した*args
と**kawrgs
は、そのまま該当Taskの引数として渡される。
なので、例えば以下のようなreminderコマンドを定義すればよい。
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self):
pass
def cog_unload(self):
self.reminder.cancel()
@tasks.loop(minutes=5.0, count=6)
async def reminder(self, ctx, content):
await ctx.send("<@{0}> {1}".format(ctx.author.id, content))
@commands.command()
async def set_reminder(self, ctx, content):
self.reminder.start(ctx, content) # ここ大事
await ctx.send("リマインダをセットしました")
これで、set_reminder
コマンドをチャットに送れば、5分ごとにあらかじめ指定した内容がメンションされる。
ポイントはself.reminder.start(ctx, content)
で、start()
に渡す引数が、そのstart()
によって起動されるTaskの引数にそのままわたることさえ押さえておけばOK。
注意
最初にも書いたようにこのコードそのものは実運用を想定していません。
set_reminderを入力後30分以内にほかの人がまたset_reminder打ったらどうなるねんとか興味は尽きませんね。
あくまでTaskに引数を渡す説明を行うための疑似コードであることをご承知ください。
(とはいえ、文法ミスのような致命的な間違いがあれば教えてください)