Commands
@bot.command()
async def foo(ctx, arg):
await ctx.send(arg)
$foo abc를 통해 명령어 호출이 가능한 것처럼 기본적으로 데코레이터 아래에 있는 함수이름이 명령어가 되어 사용된다.
from discord.ext import commands
bot = commands.Bot(command_prefix='$')
@bot.command()
async def test(ctx):
pass
# or:
@commands.command()
async def test(ctx):
pass
bot.add_command(test)
명령어 호출의 가장 기본적인 형태로 command_prefix='$'를 통해 어떤 문장으로 시작할때 명령어로 인식할것인지 설정이 가능하다. ex) $foo abc
위와 아래 모두 사용이 가능하지만 @bot.command()를 사용할경우 따로 추가해줄 필요가 없어 편리하다.
@bot.command(name='list')
async def _list(ctx, arg):
pass
명령어를 함수명과 같지 않게 하고싶을때는 bot.command의 name값을 문자열로 설정해주어 명령어를 지정할수있다.
Parameters
@bot.command()
async def test(ctx, arg):
await ctx.send(arg)
기본적으로 위치매개변수 방식으로 명령어에는 반드시 하나이상의 인자가 있으며 소스처럼 두번째 변수 arg로 받아 사용할수있는것을 알수있다. (인자의 갯수는 자유롭게 설정할수있다.) 인자값에서 공백이 들어간 문자열을 주고싶을때는 "문자열"을 이용해 주면된다.
@bot.command()
async def test(ctx, *args):
await ctx.send('{} arguments: {}'.format(len(args), ', '.join(args)))
인자갯수가 명확하지 않은 것은 위의 소스처럼하면된다.
Converters
@bot.command()
async def add(ctx, a: int, b: int):
await ctx.send(a + b)
다음처럼 명령어에 :int 를 써줌으로써 입력값을 int형으로 바꿔줄수있고
def to_upper(argument):
return argument.upper()
@bot.command()
async def up(ctx, *, content: to_upper):
await ctx.send(content)
python3의 기능으로 함수 주석을 이용한 것이다. content: to_upper처럼 content라는 변수에 to_upper함수를 지정하여 대문자로 바꿔주는 루틴을 수행한다.
if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'):
return True
elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'):
return False
bool 타입은 기존과 다르게 처리된다.
Advanced Converter
import random
class Slapper(commands.Converter):
async def convert(self, ctx, argument):
to_slap = random.choice(ctx.guild.members)
return '{0.author} slapped {1} because *{2}*'.format(ctx, to_slap, argument)
@bot.command()
async def slap(ctx, *, reason: Slapper):
await ctx.send(reason)
확장된 변환기로 사용자가 만들 수 있다. 만들때는 Converter.convert()을 이용한다.
다음 예제는 멤버중 한명을 send 입력값과 함께 뽑아준다.
@bot.command()
async def clean(ctx, *, content: commands.clean_content):
await ctx.send(content)
# or for fine-tuning
@bot.command()
async def clean(ctx, *, content: commands.clean_content(use_nicknames=False)):
await ctx.send(content)
clean_content()을 이용해 일부 상태값을 조정할수있다.
class MemberRoles(commands.MemberConverter):
async def convert(self, ctx, argument):
member = await super().convert(ctx, argument)
return [role.name for role in member.roles[1:]] # Remove everyone role!
@bot.command()
async def roles(ctx, *, member: MemberRoles):
"""Tells you a member's roles."""
await ctx.send('I see the following roles: ' + ', '.join(member))
- Member
- User
- Message (v1.1 이후)
- PartialMessage (v1.7 이후)
- TextChannel
- VoiceChannel
- StageChannel (v1.7 이후)
- StoreChannel (v1.7 이후)
- CategoryChannel
- Invite
- Guild (v1.7 이후)
- Role
- Game
- Colour
- Emoji
- PartialEmoji
디스코드 클래스를 이용해 컨버터 제작을 할 수 있다.
Special Converters
typing.Union 은 복수의 컨버터를 넣을 수 있게한다. 왼쪽에서 오른쪽순으로 작동하며 모두 실패시BadUnionArgument에러가 발생한다.
import typing
@bot.command()
async def union(ctx, what: typing.Union[discord.TextChannel, discord.Member]):
await ctx.send(what)
typing.Optional은 역참조 동작을 수행한다. 컨버터가 지정된 타입으로 못바꾸면 NONE대신 지정한 기본값으로 매개변수에 전달이 된다.
import typing
@bot.command()
async def bottles(ctx, amount: typing.Optional[int] = 99, *, liquid="beer"):
await ctx.send('{} bottles of {} on the wall!'.format(amount, liquid))
예제로 입력값으로 water을 줬지만 int형으로 못바꾸기에 기본값인 99를 주고 뒤의 liquid값을 water로 바꾼모습
Greedy컨버터는 더이상 타입변환을 할 수 없을때까지 계속변환한다.
@bot.command()
async def slap(ctx, members: commands.Greedy[discord.Member], *, reason='no reason'):
slapped = ", ".join(x.name for x in members)
await ctx.send('{} just got slapped for {}'.format(slapped, reason))
오류처리
Command.error()를 통해 오류를 처리한다.
@bot.command()
async def info(ctx, *, member: discord.Member):
"""Tells you some info about the member."""
fmt = '{0} joined on {0.joined_at} and has {1} roles.'
await ctx.send(fmt.format(member, len(member.roles)))
@info.error
async def info_error(ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send('I could not find that member...')
검사
async def is_owner(ctx):
return ctx.author.id == 316026178463072268
@bot.command(name='eval')
@commands.check(is_owner)
async def _eval(ctx, *, code):
"""A bad example of an eval command"""
await ctx.send(eval(code))
특정 사용자만 명령어를 사용하게 하기 위해 검사를 해야하는데 예제의 check데코레이터를 통해 하면서 True False로 리턴하면서 체크할수있다.
def is_owner():
async def predicate(ctx):
return ctx.author.id == 316026178463072268
return commands.check(predicate)
@bot.command(name='eval')
@is_owner()
async def _eval(ctx, *, code):
"""A bad example of an eval command"""
await ctx.send(eval(code))
is_owner() 라이브러리를 이용해 할수도있다.
def is_in_guild(guild_id):
async def predicate(ctx):
return ctx.guild and ctx.guild.id == guild_id
return commands.check(predicate)
@bot.command()
@commands.is_owner()
@is_in_guild(41771983423143937)
async def secretguilddata(ctx):
"""super secret stuff"""
await ctx.send('secret stuff')
체크를 중첩으로 할수도있다.
@bot.check
async def globally_block_dms(ctx):
return ctx.guild is not None
만약 특정 명령이 아닌 모든 명령에 적용하고 싶다면 Bot.check()를 이용하면 된다.
'꿀팁!' 카테고리의 다른 글
docker cp로 elf 파일 옮긴 후 실행 안 될때 (0) | 2021.12.01 |
---|---|
FPO 정리 잘 되어 있는 곳 (0) | 2021.11.02 |
윈도우 하위 시스템으로 ubuntu 두기 (0) | 2021.05.26 |
확장 유클리드 알고리즘으로 모듈러 연산 역산하기 (0) | 2021.05.17 |
python pip SSL ERROR (0) | 2021.02.18 |