Я пишу класс и хочу использовать асинхронную функцию в методе __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
). Есть ли более чистый способ сделать это?
Это немного неловко, но вы можете создать 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__
coro
в Task
? Это просто чтобы иметь возможность получить возвращаемое значение? Если мне не нужно возвращаемое значение, могу ли я просто выполнить run_until_complete(coro)
?