LoginSignup
1
1

More than 1 year has passed since last update.

discord.pyで元の型のままコマンド引数を受け取る方法

Last updated at Posted at 2022-01-15

環境

discord.py
discord==1.0.1
discord.py==1.7.3
python 3.9

問題点

discord.pyでは書き込みの引数は基本的に文字列にて受け取ります。
メンションやチャンネルの指定が含まれていたとしても、文字列です。

例:

test.py
# 色々と省略していますが核心部分だけ載せます
from discord.ext import commands
import discord

bot = commands.Bot(command_prefix=commands.when_mentioned_or("-"))

class TestCommand(commands.Cog):
    def __init__(self, bot):
        super().__init__()
        self.bot = bot

    @commands.command()
    async def test(self,ctx,*args):
        if args:
            for arg in args:
                await ctx.send(f'f':{type(arg)},書き込み内容{arg}')

bot.add_cog(TestCommand(bot=bot))
bot run ('TOKEN')

discord で-test あ @G1998G #メインと書き込み

結果:

型:str 書き込み内容:あ
型:str 書き込み内容:<!@827807856151796490> 
型:str 書き込み内容:<!#531806456891676162>

型は 文字列、テキスト内容は 謎の暗号(member idを<!@>で囲ったもの)となってしまいます。
私が受け取りたいのは下記の様な情報です。

型:discord.Member 書き込み内容:<Member id=827807856151796490 name='G1998G' discriminator='8843' bot=Fales nick=None guild=<Guild id=713393468499820644 name='テストギルド' shard_id=None chunked=True member_count=34>>,

文字列ではなく、上記の様に例えばdiscord.Member型で受け取る事ができれば、何かと便利です。
arg.member.idなど、discord.Member型に使用できる関数や変数をそのまま使用できます。
文字列で受け取ると、一旦<!@>を正規表現で削除して、残ったidから必要情報を抽出したりなど面倒です。
特にchannel historyを使用して過去の大量のメッセージを取得した際、もしくは*argとして可変長とした場合は非常に非効率になります。

解決方法

discord.pyではコンバーターという機能が備わっています。
型指定の形で、文字列ではなく特定の型が温存されたまま受け取ることができます。
ただしこちらには色々と不便があります。
🔻下記URLを参照
https://discordpy.readthedocs.io/ja/latest/ext/commands/api.html#converters
一番柔軟に設定できるコンバーターを使用しても、合致しない型の引数が渡されたらその引数を無かった事にしてしまったり
可変長で複数の引数を受け取った場合は 最初に合致した引数以外は全て文字列 としてしまいます。
そこで、Discord.pyのコンバーターに頼る事なく,Typing Unionを使う方法を編み出しました。

test.py
# 色々と省略していますが核心部分だけ載せます
from discord.ext import commands
import discord
from typing import Union

bot = commands.Bot(command_prefix=commands.when_mentioned_or("-"))

class TestCommand(commands.Cog):
    def __init__(self, bot):
        super().__init__()
        self.bot = bot

    @commands.command()
    # ここに注目🔻
    async def test(self,ctx,*args: Union[discord.TextChannel, discord.Member,int,str]):
        if args:
            for arg in args:
                await ctx.send(f'f':{type(arg)},書き込み内容{arg}')

bot.add_cog(TestCommand(bot=bot))
bot run ('TOKEN')

discord で-test あ  @G1998G #メインと書き込み

結果:

型:str 書き込み内容:あ
型:discord.Member 書き込み内容:<Member id=827807856151796490 name='G1998G' discriminator='8843' bot=Fales nick=None guild=<Guild id=713393468499820644 name='テストギルド' shard_id=None chunked=True member_count=34>>
型:discord.Channel 書き込み内容:TextChannel id=531806456891676162 name='メイン' position=3 nsfw=False news=False category_id=714393448499820648>

きちんと書き込み時の型を取得してくれました。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1