Использование асинхронного ожидания в методе Python __init__ - PullRequest
2 голосов
/ 15 апреля 2019

Я пишу класс и хочу использовать асинхронную функцию в методе __init__, чтобы установить некоторые переменные, необходимые для класса.Проблема в том, что я не могу этого сделать, потому что __init__ должен быть синхронным.

Вот соответствующая часть моего кода (отредактировано для простоты, логика остается прежней):

# This has to be called outside of the class
asyncDatabaseConnection = startDBConnection()

class discordBot(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Init is only run once, but we cant use async stuff here
        self.firstRun = True

    async def on_ready(self):
        # Other stuff happens here but it doesen't involve this question

        # on_ready is called when bot is ready, but can be called multiple times when running
        # (if bot has to reconnect to API), so we have to check
        if self.firstRun:
            await asyncDatabaseConnection.setValue("key", "value")
            self.firstRun = False

if __name__ == "__main__":
    # Instance class and start async stuff
    bot = discordBot()
    bot.run()

Как вы можете видеть, это для бота Discord, но это не имеет значения, это больше о логике.

Функция, которую я хочу вызвать - asyncDatabaseConnection.setValue("key", "value").

Как я уже сказал, я не могу вызвать его с __init__, потому что __init__ должен быть синхронным, поэтому вместо этого я устанавливаю firstRun на True во время вызова инициализации, а затем я могу использовать это позже дляскажите, был ли выполнен код ранее или нет

on_ready - это функция, которая вызывается, когда бот готов начать отправку / получение данных, поэтому я могу использовать ее в качестве секунды __init__,Проблема заключается в том факте, что on_ready может вызываться несколько раз в течение работы программы, что означает, что мне нужно иметь проверку firstRun, которую я описал ранее.

Это похоже на большой кодделать одну вещь при запуске (а также добавлять накладные расходы, хотя и небольшие, когда вызывается on_ready).Есть ли более чистый способ сделать это?

1 Ответ

3 голосов
/ 15 апреля 2019

Это немного неловко, но вы можете создать Task, затем запустить его и получить его результат. Если вы делаете это часто, это может помочь написать вспомогательную функцию:

def run_and_get(coro):
    task = asyncio.create_task(coro)
    asyncio.get_running_loop().run_until_complete(task)
    return task.result()

class discordBot(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        run_and_get(asyncDatabaseConnection.setValue("key", "value"))

Это зависит от наличия работающего цикла обработки событий, который, я считаю, Client.__init__ устанавливает

...