今天繼續介紹應用指令的參數,會著重在如何避免使用者輸入不合適的參數。
進度

這應該算是應用指令的最後一篇了…
程式的防呆設計
相信各位程式開發者應該都有這樣的經驗:開發了一個功能,但偏偏使用者並不按照原本設想的方式使用,

因此,開發者往往都需要盡量設想各種可能,並且做出對應的防範措施。而可以讓使用者自行設定參數的斜線指令也是如此,開發者需要防範使用者輸入不合適的參數。
在昨天的文章有提到,如果使用者輸入的型別不正確,就會出現錯誤提示,提醒使用者要輸入正確的格式 (例如:請輸入有效的整數)。但有時候,光是型別還不夠,因此,接下來會介紹更多限制的方法,包含:
- 選項
- 範圍 (數字)
1. 選項
如果參數的選項不多,直接把所有選項都設定好,並要求使用者只能從中選一個,會是一個很好的選擇。而設定選項的方式也有幾種不同的寫法:
Literal
最簡單的就是使用 Literal
,將所有選項列出來。
1 2 3 4 5 6 7 8 9 10 11 12 13
| from typing import Literal
@client.tree.command(description="點餐") async def order( interaction: discord.Interaction, tea: Literal["綠茶", "紅茶", "奶茶"], size: Literal["大杯", "中杯", "小杯"], ): await interaction.response.send_message(f"點餐結果:{tea}{size}")
|
之後設定參數時,就只能從上面所列的選項中進行選擇了。



Enum
除了 Literal
,也可以使用 Enum
。使用 Enum
除了可以更方便管理這些常數們,也可以做成 key、value 對,讓程式可以依據需求選擇要使用的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| from enum import Enum
class Tea(Enum): green_tea = "綠茶" black_tea = "紅茶" milk_tea = "奶茶"
class Size(Enum): small = "小杯" medium = "中杯" large = "大杯"
@client.tree.command(description="點餐") async def order( interaction: discord.Interaction, tea: Tea, size: Size, ): await interaction.response.send_message(f"點餐結果:{tea.value}{size.value}")
|
這邊顯示的選項就會是英文,函數內再用 .value
來取得中文。


不過,由於 Enum
本身寫法上的限制,很難反過來改成顯示中文選項,但取得英文的值。想要做到的話,就可以考慮使用下一個方法:choice
。
choice
直接來看範例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from discord.app_commands import Choice
@client.tree.command(description="點餐") @app_commands.choices(tea=[ Choice(name='綠茶', value='green_tea'), Choice(name='紅茶', value='black_tea'), Choice(name='奶茶', value='milk_tea'), ]) @app_commands.choices(size=[ Choice(name='小杯', value='small'), Choice(name='中杯', value='medium'), Choice(name='大杯', value='large'), ]) async def order( interaction: discord.Interaction, tea: Choice[str], size: Choice[str], ): await interaction.response.send_message(f"點餐結果:{tea.name}{size.name}")
|
這個範例還是一樣回傳中文,但如果需要取得英文,改用 .value
取值就好。
2. 範圍
在某些時候,要把所有選項列出來並不容易 (例如:飲料的杯數),但如果選項是在某個範圍內的數字的話,就可以使用 Range
。
來看一下這個範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from discord.app_commands import Range
@client.tree.command(description="點餐") async def order( interaction: discord.Interaction, tea: Literal["綠茶", "紅茶", "奶茶"], size: Literal["大杯", "中杯", "小杯"], number: Range[int, 1, 10], ): await interaction.response.send_message(f"點餐結果:{tea}{size} {number}杯")
|
執行後,在輸入數量前,並沒有提示:

但按下 Enter 送出後,就會跳出錯誤提示,要求必須在範圍內才可以。

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。
小結
今天算是「暫時」把應用指令收尾了,明天會介紹 bot 指令框架,把目前的觸發條件、應用指令等的寫法重新包裝XD
今天是 PyCon 第二天,有幾個跟 FastAPI 相關的演講,感覺格外親切 XD