discord.py

덤프버전 :


discord.py

파일:discord.py logo.png

최신 버전
2.3.1
필요 파이썬 버전
3.8 이상
상태
개발 중
링크
Github 공식 Discord 서버
1. 개요
2. 개발 중단 선언과 복귀
3. 제작 시 유의 및 주의해야할 점
3.1. 제작 전
3.2. discord와 discord.ext
3.2.1. discord.Client와 discord.ext.commands.Bot의 호환
3.3. 개발 중 및 유지
4. 업데이트
5. 프로그래밍 예제
5.1. discord.ext.commands.Bot
5.1.1. 기본 대화 및 출력
5.2. discord.Client
5.2.1. 기본 대화 및 출력
5.3. Discord.py 2.0
5.3.1. 기본 대화 및 출력



1. 개요[편집]


discord.py는 파이썬용 디스코드 봇 API Wrapper 중 가장 간편하고 많이 쓰이는 라이브러리 중 하나이다. 하지만 다른 언어에 비해 상대적으로 쉽다는 것이지 기본적인 파이썬 사용 방법을 모른다면 당연히 아무것도 할 수 없으므로 꼭 기초적인 문법과 디버깅 방법을 익히고 공부하자. 사실 개발하다 보면 코루틴과 비동기 라이브러리 asyncio정도까지는 공부해야 한다는 것을 느끼게 되니 비동기 또한 익혀두는 것이 좋다.


2. 개발 중단 선언과 복귀[편집]


2021년 8월 28일, discord.py의 개발을 중단했다. 해당 입장문
개발을 중단한 이유를 정리하자면 다음과 같다.
  • 디스코드가 공식 API 문서를 공개[1]하면서 수많은 기능과 지원을 약속받음.
  • 하지만 약속은 제대로 지켜지지 않았고 디스코드 직원들은 향후 3년 동안 라이브러리 개발자들의 피드백을 소홀히 함.
  • 디스코드 API 서버는 직원들과 라이브러리 개발자들이 변경 사항에 대해 논의할 수 있는 곳이었으나, 시간이 지나면서 대화는 점점 단절되어 감.
  • 그러던 중, 디스코드 직원들은 디스코드 API 서버 대신 Discord Infrastructure[2]에만 변경 사항을 공유하기 시작했다. 하지만 라이브러리 개발자들이 해당 서버에 초대를 받지 못함. [3]
    • 문제는 라이브러리에 큰 영향을 받는 변경 사항을 위 서버의 개발자들과만 논의하였다는 것. 대부분의 라이브러리 개발자들은 이를 탐탁지 않게 여김.
  • 2020년 4월 7일, 디스코드 블로그에 미래에 대한 계획이 발표됨. 여기에는 수많은 기능[4]과 봇 인증[5]이 공개됨.
    • 봇 인증을 받기 위해서는 국가에서 발행한 신분증을 사용해야 하는데 개발자들은 개인정보를 침해한다고 반발했으나 검토가 이뤄지지 않음.
  • 2020년 7월과 8월경, Discord Infrastructure에 슬래시 커맨드[7]에 대하여 이야기함.
    • 문제는 슬래시 명령어를 도입하면서 기존에 쓰고 있는 메시지형 명령어[6] 기능이 제한된다.
    • 업데이트가 된다면 이를 모두 슬래시 명령어로 바꿔야 하는데 discord.py 라이브러리 자체를 싹 갈아엎어야 한다는 것이다.
  • 인증 시스템이 도입되고 디스코드 직원들의 적절한 협의 없는 급격한 변화로 인한 잦은 변화로 라이브러리 작업에 대한 동기가 줄어듦.

현재 포크된 버전이 존재한다. pycord nextcord

2022년 3월 6일, discord.py 개발을 다시 시작한다고 발표했다. 해당 공지

3. 제작 시 유의 및 주의해야할 점[편집]



3.1. 제작 전[편집]


당연하지만 먼저 Python을 설치해야 한다. http://python.org에서 본인의 OS에 맞게 설치하자. 편집기는 IDLE이 같이 설치되기는 하지만 PyCharm이나 Visual Studio Code 등의 IDE를 설치하는 것을 추천한다.

파이썬 버전은 1.7.3에서는 3.5 이상 3.9 미만만을 지원했으나 2022년 8월 18일 pypi에 2.0.0이 공식 릴리즈되며 3.8 이상 3.10 이하로 변경되었다.

discord.py 2가 베타 테스트를 마친 후 pypi에 공식 릴리즈되어 있으니 가급적 최신 버전을 사용하는 것을 추천한다.

3.2. discord와 discord.ext[편집]


몇 년 전까지만 해도, discord.py 강의는 1.0.0 이하의 버전[8]을 위주로 다루었다.
그러나 현재는 discord.ext.commands 기반의 강의도 많이 나와 있으니, 위에서 말한 단점들에도 불구하고 discord.py를 배워서 쓰고 싶다면 commands 기반의 강의를 보길 바란다.

Client() 예제:
import discord

client = discord.Client(intents=discord.Intents.default())

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

@client.event
async def on_message(message):
    if message.content.startswith('!ping'):
        await message.channel.send('pong')

client.run('token')


이렇게 discord.Client를 사용하는 방법은 코드량이 많아질 수록 지저분해지고 세분 및 체계화가 어렵다. 이러한 점을 해결하기 위해 추가된게 discord.ext.commands이다.

github에 소개 되어있는 commands.Bot 예제:
import discord
from discord.ext import commands

bot = commands.Bot(command_prefix='!')

@bot.event
async def on_ready():
    print('Logged in as')
    print(bot.user.name)
    print(bot.user.id)
    print('------')

@bot.command()
async def ping(ctx):
    await ctx.send('pong')

bot.run('token')


API에 대해 이해도가 조금 쌓여있는 상태라면 commands.Bot이 훨씬 체계적이며 깔끔하고 유연하며, 쉽다는 것을 알 수 있다. 또한 cooldown, has_permission 등의 데코레이터가 만들어져 있어 개발 효율성도 좋으니 commands.Bot을 쓰는 것이 낫다.

3.2.1. discord.Client와 discord.ext.commands.Bot의 호환[편집]


discord.Client의 on_message에서 commands.Bot으로 마이그레이션할경우 원래의 on_message와 commands.Bot을 혼용 가능하다.
그러나 막상 코드를 합치고 실행시켜보면 on_message만 작동하며 나머지는 제대로 작동하지 않는 것을 발견할 수 있다[9].
이는 `bot.process_commands(message)`를 on_message의 맨 마지막 줄에 붙여주면 잘 작동하는 것을 볼 수 있다.
하지만 나중을 생각할때 commands로 모두 전환시키는 것이 좋다.


3.3. 개발 중 및 유지[편집]


만약 정상적으로 작동했던 봇이 어느날 정상 작동이 되지 않는다면, discord.py의 버전을 체크해봐야한다. 업데이트되어 호환이 안되거나 구버전 및 상위 버전 함수를 사용해 오류가 날 가능성도 있다. 해결법은 전에 사용하던 버전으로 재설치하면 된다.

이건 discord.py를 사용하는 봇 외에 모두 공통으로 적용되는 점이지만, 봇 토큰을 타인에게 절대 노출하면 안된다. 봇 토큰은 각 봇들의 신분증처럼 연결중인 봇이 어떤 봇인가 증명하는 수단이다. 노출되어 문제가 발생한다면 누군가 내 껍데기를 뒤집어 씌고 본인인 것 마냥 행세하는 격의 일이 벌어질 수 있다.

개발을 시작할때부터 테스트를 염두에 두고 개발하는 것이 좋다. 봇 호스팅과 자신의 코드가 같이 실행될경우 개발 중 버그가 제3자에게 노출되어 문제가 생길수도 있으며 또한 호스팅에 바로 올려서 테스트하는경우 코드가 유실될 수 있기 때문이다[10].

commands.Bot에 어느 정도 익숙해진 경우, 유지보수를 위해 코드가 아주 간단한[11] 경우를 제외하면 Cog를 사용하는것을 매우 강력히 추천한다.

python 3.9 업데이트 관련해서 문제가 생겼다.

pip install discord.py

명령어를 입력하면, Falied to build yarl multidict라는 문구와 함께 다운로드에 실패한다.https://github.com/Rapptz/discord.py/discussions/5898#discussioncomment-91100
이는 파이썬이 3.9 버전으로 업데이트 하면서 생긴 wheels 제공 관련 문제로, [12] python 3.8로 다운그레이드하거나 MS visual c++ build tools 2015 이상을 설치하면 대부분 된다.

4. 업데이트[편집]


discord.py는 깃허브에서 개발되고 있으며, 릴리즈가 나올 때마다 pypl에 업데이트가 되는 식이다. 이에 따라 아직 정식 릴리즈에 추가 되지 않은 기능들을 미리 사용하려면 깃허브에서 git을 이용해 업데이트를 해야 한다.
업데이트 방법:

pip install -U git+https://github.com/Rapptz/discord.py.git

깃허브에 올라온 모듈을 그대로 업데이트시키는 명령이므로 (정식 릴리즈 판에 비해) 버그, 오류가 있을 수 있지만 아직 테스트 중인 기능들을 미리 사용해 볼 수 있다.

5. 프로그래밍 예제[편집]


오래되고 단점이 많아 추천되지 않는 discord.Client보단 discord.ext.comamnds.Bot 클래스를 주로 이용해서 작성해주세요. 입문용으로 많이 선호하는만큼 discord.py와 관련된 함수에 설명 주석을 넣어주면 좋습니다. 아래 예제는 예제인만큼 아래 방식뿐만아닌 다른 방식으로도 구현이 가능할 수 있습니다. 만약 다른 방식이지만 의미가 미미한 수준이면 추가는 삼가 주세요. 파이썬 자체에 대한 설명은 Python 또는 해외 자료를 통해 참고해주세요.


5.1. discord.ext.commands.Bot[편집]



5.1.1. 기본 대화 및 출력[편집]


discord.Client의 메서드는 모두 사용이 가능한데, 이는 discord.Client를 commands.Bot이 상속하기 때문이다.

from discord.ext import commands

bot = commands.Bot(command_prefix='!')

'''
봇이 반응을 해야하는 명령어인지 구분하기 위해 메세지 앞에 붙이는 접두사(prefix)를 설정합니다. 현재 !로 
설정되어있습니다. 이곳을 변경시 해당 문자로 명령어를 시작해야합니다. ext에선 discord.Client처럼 
str.startswith 메서드를 사용할 필요가 없습니다.
'''

@bot.event
async def on_ready():
    print('Logged in as')
    print(bot.user.name) # 토큰으로 로그인 된 bot 객체에서 discord.User 클래스를 가져온 뒤 name 프로퍼티를 출력
    print(bot.user.id) # 위와 같은 클래스에서 id 프로퍼티 출력
    print('------')

@bot.command()
async def ping(ctx):
    await ctx.send(f'pong! {round(round(bot.latency, 4)*1000)}ms') # 봇의 핑을 pong! 이라는 메세지와 함께 전송한다. latency는 일정 시간마다 측정됨에 따라 정확하지 않을 수 있다.

@bot.command(name="1234")
async def _1234(ctx):
    await ctx.send("5678")
#파이썬 문법에 따라 함수를 만들 때에는 첫글자에는 숫자를 넣을 수 없는데, 숫자를 사용하고싶다면 함수 이름 자리는 다른 아무것으로 대체하고 괄호 안에 name=""을 사용하여 명령어를 제작할 수 있다.

bot.run('token')


5.2. discord.Client[편집]



5.2.1. 기본 대화 및 출력[편집]


import discord

client = discord.Client()

@client.event
async def on_ready(): # 봇이 실행 준비가 되었을 때 행동할 것
    print('Logged in as')
    print(client.user.name) # 클라이언트의 유저 이름을 출력합니다.
    print(client.user.id) # 클라이언트의 유저 고유 ID를 출력합니다.
    # 고유 ID는 모든 유저 및 봇이 가지고있는 숫자만으로 이루어진 ID입니다.
    print('------')

@client.event
async def on_message(message): # 입력되는 메세지에서 찾기
    if message.content.startswith('!ping'): # 만약 메세지가 '!ping'으로 시작된다면
        await message.channel.send('pong') # 클라이언트는 메세지가 올라온 채널에 'pong'을 보냅니다.
    elif message.content.startswith('!pong'):
        await message.channel.send('ping!')

    '''
    on_message에서 또다른 명령어 추가를 위해서는 조건문을 추가해야 합니다.
    여기서는 elif 사용을 추천하는데, 명령어가 일치하는지에 대한 조건문에서 참이 나온 경우에는 나머지들이 모두 거짓이 될 수밖에 없어 연산이 불필요하기 때문입니다
    '''
client.run('token')

만약 봇의 메세지는 반응하고싶지 않다면, on_message 최상단에
if message.author == client.user: # 만약 메시지를 보낸 사람과 봇이 서로 같을 때
    return

if message.author.bot: # discord.User.bot 프로퍼티가 참일 때. 이 조건문을 사용할경우 위의 조건문이 필요치 않다
    return

을 하면 반응하지 않는다.[13]

아래는 client를 사용할때 더 깔끔하고 간단하게 쓸 수 있는 방법
import discord

client = discord.Client()
prefix ='!' # 접두사

@client.event
async def on_ready(): 
    print('Logged in as')
    print(client.user.name) 
    print(client.user.id)
    print('------')

@client.event
async def on_message(message): 
    cmd = message.content.split(prefix)[1].split()[0] # 명령어를 저장한다
    args = message.content.split(cmd)[1].split() # 공백을 기준으로 args를 저장한다
    if cmd == 'ping': # 위 두 코드와 합쳐져 message.content.startswith('!ping')과 똑같은 조건에만 참이 된다
        await message.channel.send('ping!')
client.run('token')



5.3. Discord.py 2.0[편집]



5.3.1. 기본 대화 및 출력[편집]


import discord
from discord import app_command

intents = discord.Intents.default()
intents.message_content = True

class MyBot(commands.Bot):
    def __init__(self):
        super().__init__(
            command_prefix="!",
            intents=intents.all(),
            sync_command=True,
            application_id= #디스코드 봇의 application id를 입력한다.
        )
        
    async def setup_hook(self):
        await bot.tree.sync()

    async def on_ready(self):
        print("ready!")
        
        activity = discord.Game("상태 메세지")
        await self.change_presence(status=discord.Status.online, activity=activity)

    @app_command.command(name="ping")
    async def ping(self, ctx: commands.Context) -> None:
        await ctx.send("pong!")

bot = MyBot()
bot.run("token")

파일:크리에이티브 커먼즈 라이선스__CC.png 이 문서의 내용 중 전체 또는 일부는 2023-11-06 01:34:58에 나무위키 discord.py 문서에서 가져왔습니다.

[1] 공개되지 않았을 때는 다른 개발자들과 함께 API를 리버스 엔지니어링하여 라이브러리를 작성하였다.[2] 해당 서버는 대형 봇 개발자들에게 인프라 상태를 공유하는 개인 서버였지만 곧 봇 개발자들과 소통하는 사실상 반공식 서버가 되었다.[3] 그나마 대형 봇 개발을 도운 2명의 라이브러리 개발자들이 초대받았다[4] context 메뉴, 버튼, 임시 메시지 등[5] 봇이 초대된 서버가 75개가 넘을 경우 봇 인증을 받을 수 있다. 인증되지 않은 봇은 최대 100개의 서버에만 초대할 수 있다.[6] !ban >ban 과 같은 접두사 메시지[7] /로 시작하는 명령어 시스템[8] discord.Client만을 사용[9] on_message의 무한반복이 commands의 실행을 막기 때문[10] 유실은 깃허브로 해결이 가능하긴 하지만 그러지 않는 편이 좋다.[11] 명령어가 1~2개로 매우 적은 상황 등[12] 의존성 라이브러리인 aiohttp, yarl, multidict가 문제가 되고 있다.[13] 파이썬은 항상 위에서 아래로 한줄씩 구동된다는 점을 알아야 한다. 인터프리터 언어의 특징으로, 만약 저 코드가 명령어 아래에 있다면 먼저 실행되지 않아 소용이 없다.