LoginSignup
7
6

discord.pyでアプリケーションコマンドを実装する

Last updated at Posted at 2024-03-08

はじめに

discord.pyは近年アップデート続きで情報が不確かで、日本語の文献が少なかったため書いてみました。

この記事では簡単にアプリケーションコマンド(スラッシュコマンド)を実装するための方法を解説します。

この記事の対象者

  • ある程度Pythonの知識があり、discord.pyでアプリケーションコマンドを実装したい。

前提知識

  • 基本的なPythonの記法と仕様を理解している
  • discord.pyの基本的な使い方を知っている

実装

基本的な実装

以下のコードは引数を取らない基本的な実装です:

from os import environ

import discord
from discord.ext import commands

intents = discord.Intents.all()
bot = commands.Bot(intents=intents, command_prefix="!")
tree = bot.tree

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user.name}.")
    await tree.sync()
    print("Synced slash commands.")


@tree.command(name="ping", description="レイテンシを計測します")
async def ping(ctx: discord.Interaction):
    text = f'Pong! {round(self.bot.latency*1000)}ms'
    embed = discord.Embed(title='Latency', description=text)
    await ctx.response.send_message(embed=embed)

bot.run(environ["TOKEN"])

変数treeにはbot.tree(型はCommandTree)が渡され、これがアプリケーションとのインタラクションを扱う変数になります。

@tree.command()デコレータを使ってアプリケーションコマンドが実装できます。

tree.command() デコレータの引数

  • name: アプリケーションコマンドの名前を指定する引数
  • description: アプリケーションコマンドの説明文を指定する引数(optional)
    その他の引数は公式リファレンスを参照してください。

ctx(コンテキスト)にはdiscord.Interactionが入り、これのresponse.send_message()などのメソッドを利用してインタラクションへの応答などの処理が可能です。

引数をとるコマンドの実装

基本的な引数の実装

@tree.command(name="add", description="引数の総合値を算出します")
async def add(ctx: discord.Interaction, val1, val2, val3):
    try:
        result = str(int(val1) + int(val2) + int(val3)) # 基本的に引数はstr型で渡されます
    except Exception as e:
        result = "Error: " + str(e)
    text = f'`{}`'
    embed = Embed(title='Result:', description=text)
    await ctx.response.send_message(embed=embed)

@tree.command()デコレータの引数を増やすことでユーザーから引数を受け取ることができるようになります。

引数に説明を付与する

from discord.app_commands import describe

@tree.command(name="add", description="引数の総合値を算出します")
@describe(val1="第1引数")
@describe(val2="第2引数")
@describe(val3="第3引数")
async def add(ctx: discord.Interaction, val1, val2, val3):
    try:
        result = str(int(val1) + int(val2) + int(val3))
    except Exception as e:
        result = "Error: " + str(e)
    text = f'`{}`'
    embed = Embed(title='Result:', description=text)
    await ctx.response.send_message(embed=embed)

@discord.app_command.describe()デコレータを利用してアプリケーションコマンドの引数に説明を付与することができます。
構文はdescribe(引数名=説明)です。

引数をオプショナル(任意)にする

from discord.app_commands import describe

@tree.command(name="add", description="引数の総合値を算出します")
@describe(val1="第1引数")
@describe(val2="第2引数")
@describe(val3="第3引数")
async def add(ctx: discord.Interaction, val1, val2 = 0, val3 = 0):
    try:
        result = str(int(val1) + int(val2) + int(val3))
    except Exception as e:
        result = "Error: " + str(e)
    text = f'`{}`'
    embed = Embed(title='Result:', description=text)
    await ctx.response.send_message(embed=embed)

デコレータ内の引数を予め指定しておくことにより、アプリケーションコマンド上でもデフォルトの値が指定できます。

引数の型を指定する

from discord.app_commands import describe

@tree.command(name="add", description="引数の総合値を算出します")
@describe(val1="第1引数")
@describe(val2="第2引数")
@describe(val3="第3引数")
async def add(ctx: discord.Interaction, val1: int, val2: int = 0, val3: int = 0):
    try:
        result = str(int(val1) + int(val2) + int(val3))
    except Exception as e:
        result = "Error: " + str(e)
    text = f'`{}`'
    embed = Embed(title='Result:', description=text)
    await ctx.response.send_message(embed=embed)

型アノテーションを追加することで引数の型を指定できます。(str=文字列, int=整数値, float=浮動小数点数)

引数のデフォルト値と型の指定を併用する際、デフォルト値はその型と同じである必要があります。

例:

val1: int = 0
val2: str = ""
val3: float = .0
val4: discord.Member = None # NoneTypeはどの型に対しても有効

数値を指定する引数に範囲を指定する

from discord.app_commands import Range, describe

r = Range[int, -100, 100]

@tree.command(name="add", description="引数の総合値を算出します")
@describe(val1="第1引数")
@describe(val2="第2引数")
@describe(val3="第3引数")
async def add(ctx: discord.Interaction, val1: r, val2: r = 0, val3: r = 0):
    try:
        result = str(val1 + val2 + val3)
    except Exception as e:
        result = "Error: " + str(e)
    text = f'`{result}`'
    embed = Embed(title='Result:', description=text)
    await ctx.response.send_message(embed=embed)

discord.app_command.Rangeクラスを使ってアノテーションをすることで範囲を指定できます。
公式リファレンスからの引用:

  • Range[int, 10] は最小値10、最大値なしを意味します
  • Range[int, None, 10] は最小値なし、最大値10を意味します
  • Range[int, 1, 10] は最小値1、最大値10を意味します
  • Range[float, 1.0, 5.0] は最小値1.0、最大値5.0を意味します
  • Range[str, 1, 10] は最小1文字、最大10文字を意味します

終わりに

最後まで読んで頂きありがとうございます。不備があれば是非コメントで指摘して下さい。

7
6
0

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
7
6