2017-06-23 1 views
1

Donc, je suis en train d'implémenter un Discord Bot en utilisant discord.py, et j'essaie d'appeler dynamiquement des fonctions basées sur des commandes. J'ai été capable de tester les appels de fonctions dynamiques avec exec(), mais ils semblent se désintégrer avec les appels asynchrones nécessaires pour discord.py.Appelez dynamiquement les fonctions asynchrones avec exec()

Donc ce que j'essaie de faire avec cet exemple serait d'appeler la fonction hello et d'imprimer Hello World en discordance en tapant! Hello dans le chat.

@client.event 
async def on_message(message): 
    call = 'await ' + message.content.lower()[1:] + '(message)' 
    exec(call) 

async def hello(message): 
    await client.send_message(message.channel, 'Hello World') 

Malheureusement, ce code ne semble pas faire quoi que ce soit, je suppose que la façon dont les poignées exec() les appels asynchrones. Toute aide serait appréciée.

Répondre

1

Au lieu de exec() utiliser globals() pour obtenir votre fonction:

import asyncio 


async def main(): 
    s = "foo" 
    param = "hello" 
    coro = globals().get(s) 
    if coro: 
     result = await coro(param) 
     print("got:", result) 
    else: 
     print("unknown function:", s) 


async def foo(param): 
    print(param) 
    await asyncio.sleep(0.11) 
    return ":-)" 


loop = asyncio.get_event_loop() 
response = loop.run_until_complete(main()) 
loop.close() 

Cependant, ce qui permet à l'utilisateur d'accéder à quoi que ce soit dans globals() pourrait BWE dangereuse, au lieu, il serait préférable de whitelist vos commandes, par exemple en utilisant:

import asyncio 

my_commands = {} 


def register(cmd): 
    my_commands[cmd.__name__] = cmd 
    return cmd 


async def main(): 
    s = "foo" 
    param = "hello" 
    coro = my_commands.get(s) 
    if coro: 
     result = await coro(param) 
     print("got:", result) 
    else: 
     print("unknown function:", s) 


@register 
async def foo(param): 
    """I am the mighty foo command!""" 
    print(param) 
    await asyncio.sleep(0.11) 
    return ":-)" 



loop = asyncio.get_event_loop() 
response = loop.run_until_complete(main()) 
loop.close() 

Voir aussi:

for k, v in my_commands.items(): 
    print("{}: {}".format(k, v.__doc__ or "no docs"))