Использование асинхронного ожидания в методе Python __init__

1

Я пишу класс и хочу использовать асинхронную функцию в методе __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 во время вызова init, а затем я могу использовать это позже, чтобы узнать, был ли выполнен код раньше или нет

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

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

  • 0
    Я бы сказал, что у вас должна быть функция, которая выполняет асинхронную задачу, а затем синхронно инициализирует и возвращает экземпляр класса.
Теги:
async-await
discord.py

1 ответ

1

Это немного неловко, но вы можете создать 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__

  • 0
    Кажется, это может решить мою проблему. Почему вы превращаете coro в Task ? Это просто чтобы иметь возможность получить возвращаемое значение? Если мне не нужно возвращаемое значение, могу ли я просто выполнить run_until_complete(coro) ?
  • 0
    Я думаю, что если вы сделаете это, он просто создаст Задачу или Будущее для этой сопрограммы под капотом, поэтому не должно быть никаких последствий для производительности.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню