---
tags: 1101,Discord Bot
---
# Discord Bot#3 Cog
## Cog簡介
- 將我們所有的指令整理成一個一個的**物件**
- 將這些指令做成物件後,我們的機器人本體(bot.py)就只需要負責載入或移除這些物件
- **完成之後,我們就可以更方便地去DEBUG囉!**
## Cog實作
### 幫你的指令及事件搬家
1. 在bot.py的所在的資料夾中,開一個資料夾Cog
![](https://i.imgur.com/VYPfoms.png)
2. 在Cog資料夾底下新增 event.py image.py main.py 三個檔案
![](https://i.imgur.com/YUaVaDV.png)
3. 打開main檔案,開始把指令搬家囉
4. 先打出這個基本的Cog結構
- **class Main(command.Cog)**: 一個叫做 Main 的物件,它擁有 command.Cog 的特性,裡面會存放各種你想放的指令以及事件
- **__ init __(self, bot)**:生成 Main 這個物件的時候會呼叫的 function, 這裡的用意是想讓Main這個物件也可以讀取到bot.py裡的 Bot物件
- **def setup(bot)**: 這個函式會在每次載入Main這個Cog的時候執行,讓bot.py裡的機器人載入Cog
```python=
import discord
from discord.ext import commands
class Main(commands.Cog):
def __init__(self, bot):
self.bot = bot
def setup(bot):
bot.add_cog(Main(bot))
```
5. 將 ping 和 purge 兩個指令剪下貼上到class Main裡面
6. 修改 ping 和 purge 指令
>Note: 直接寫在 bot.py和寫成Cog主要有兩個不同,第一是修飾器,第二個則是 function的參數一定要有self,Cog因為是一個class,所以每個function的**第一個**參數都必須是self
- 修飾器比較
| | command | event |
|:------:|:-------------------:|:------------------------:|
| bot.py | @bot.command() | @bot.event |
| Cog | @commands.command() | @commands.Cog.listener() |
- Main.py (記得bot也要改成self.bot喔)
```python=
import discord
from discord.ext import commands
class Main(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
async def ping(self, ctx):
await ctx.send(self.bot.latency)
@commands.command()
async def purge(self, ctx, num=1):
deleted = await ctx.channel.purge(limit=num+1)
await ctx.send(f'{len(deleted)} messages deleted!')
def load(bot):
bot.add_cog(Main(bot))
```
7. 接著把傳送圖片相關的指令搬到 image.py,注意這裡也會需要另外import random和json兩個module,且在程式一開始也需要讀取json檔案
```python=
import discord
from discord.ext import commands
import random
import json
with open('setting.json', 'r', encoding='utf8') as jsonFile:
setting = json.load(jsonFile)
class Image(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
async def image(self, ctx):
dcFile = discord.File(random.choice(setting['image']))
await ctx.send(file=dcFile)
@commands.command()
async def webimage(self, ctx):
await ctx.send(random.choice(setting['webimage']))
def setup(bot):
bot.add_cog(Image(bot))
```
8. 最後是 event.py,我們需要把on_member_join,on_member_remove,on_message三個指令搬至 event.py
>Note: 由於這個Cog全部都是event,修飾器是用@commands.Cog.listener(),而不是之前的@commands.command()
```python=
import discord
from discord.ext import commands
import json
with open('setting.json', 'r', encoding='utf8') as jsonFile:
setting = json.load(jsonFile)
class Event(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener()
async def on_member_join(self, member):
ch = self.bot.get_channel(int(setting['channel_id']))
await ch.send(f'{member} Ya hello')
@commands.Cog.listener()
async def on_member_remove(self, member):
ch = self.bot.get_channel(int(setting['channel_id']))
await ch.send(f'{member} Bye bye')
@commands.Cog.listener()
async def on_message(self, msg):
if 'Yo' in msg.content and msg.author != self.bot.user:
await msg.channel.send('Yo')
await self.bot.process_commands(msg)
def setup(bot):
bot.add_cog(Event(bot))
```
### 在bot.py中使用Cog
- 在bot.py的run前面加入下列程式碼,它會找到Cog資料夾中所有的py檔案,並用load_extension載入這些cog,**記得在檔案開頭加入 from pathlib import Path**
>Note: 這裡的load功能其實就有點像是程式開頭的from ... import ...
```python=
for cog in [p.stem for p in Path(".").glob("./Cog/*.py")]:
bot.load_extension(f'Cog.{cog}')
print(f'Loaded {cog}.')
print('Done.')
```
### 實用的Debug函式
- load
```python=
@bot.command()
async def load(ctx, ext):
bot.load_extension(f'Cog.{ext}')
await ctx.send(f'{ext} loaded successfully.')
```
- unload
```python=
@bot.command()
async def unload(ctx, ext):
bot.unload_extension(f'Cog.{ext}')
await ctx.send(f'{ext} unloaded successfully.')
```
- reload (DEBUG神器)
```python=
@bot.command()
async def reload(ctx, ext):
bot.reload_extension(f'Cog.{ext}')
await ctx.send(f'{ext} reloaded successfully.')
```
## 小小指令報錯功能
- 我們可以直接使用內建的 on_command_error 事件,幫助我們把這些錯誤訊息傳送至頻道
![](https://i.imgur.com/C6uF0A2.png)
- 示意圖
![](https://i.imgur.com/dj05P9k.png)
```python=
@commands.Cog.listener()
async def on_command_error(self, ctx, err):
await ctx.send(err)
```
## 一些自學資源
[Proladon - Code a Discord bot](https://www.youtube.com/watch?v=odIQEJW0m1M&list=PLSCgthA1Anif1w6mKM3O6xlBGGypXtrtN&ab_channel=Proladon)
[彭彭 - Python 入門課程](https://www.youtube.com/playlist?list=PL-g0fdC5RMboYEyt6QS2iLb_1m7QcgfHk)