异步初始化时将参数传递给python类
Posted
技术标签:
【中文标题】异步初始化时将参数传递给python类【英文标题】:Passing parameter to a python class when initializing it asynchronously 【发布时间】:2018-09-16 22:29:39 【问题描述】:我在看this answer,他们解释了如何使用__await__
方法异步初始化一个类。问题是:在等待类的初始化时,是否可以像同步初始化一样传递参数?
换句话说,我希望能够做到
my_class = await MyClass(my_parameter)
,但是我无法以任何方式使其工作。
我是否应该像this answer 那样回退到使用经典的__init__
?
【问题讨论】:
【参考方案1】:您应该只使用__init__
。您正在创建一个常规类实例首先,然后在该实例上等待。这是两个独立的操作。
例如,您可以先创建实例,然后单独等待它:
my_class = MyClass(my_parameter)
result_from_coroutine = await my_class
或者您可以从中创建一个任务并让事件循环执行它
my_class = MyClass(my_parameter)
task = asyncio.create_task(my_class) # the loop will await the task
# ...
if task.done():
result_from_coroutine = task.result()
__await__
方法是 await
或事件循环用来驱动协程的方法。同样的分离也适用于协程函数(用async def
定义);当您调用它们时,它们也会创建一个新的协程对象,您不必立即等待它们。您可以在其他时间对结果使用await
。
如果您正在寻找异步实例创建,那么您可以通过将__new__
method 变成协程来解决这个问题:
>>> class Async:
... async def __new__(cls):
... instance = super().__new__(cls)
... return instance
...
>>> Async()
<coroutine object Async.__new__ at 0x103654148>
等待协程将创建实际实例并返回它。
考虑到这确实意味着__init__
方法将被跳过;后者仅在__new__
方法直接返回类(或子类)的实例时调用,协程不是这样的实例。您必须自己明确地这样做:
class Async:
async def __new__(cls, *args, **kwargs):
instance = super().__new__(cls)
instance.__init__(*args, **kwarg)
return instance
此时您可以决定将__init__
方法也设为协程。
请注意,这确实违反了规定。我会把调用依赖协程推迟到以后。
例如,您可以将参数存储到实例上的类中,并在等待实例时使用这些参数(通过调用__await__
),就像您链接到建议的帖子一样。
【讨论】:
我之所以进行异步初始化是因为我正在等待一些方法,这些方法需要在创建类后立即运行,但是因为它们是私有方法,所以我没有想把它们称为类本身的“外部”。 @FedericoCorazza:你不能异步创建实例。 @FedericoCorazza:那是因为创建实例的过程不是由__init__
处理的,这只是一个名为在实例已经创建之后的钩子。
这很有趣,但我同意,我应该稍后再调用 awaitables。【参考方案2】:
换句话说,我希望能够做到
my_class = await MyClass(my_parameter)
,但是我无法以任何方式使其工作。
您可以通过实现__await__
使MyClass
可等待:
class MyClass:
def __init__(self, delay):
self.delay = delay
async def __await__(self):
await asyncio.sleep(self.delay)
asyncio.run(MyClass(2)) # sleeps 2 seconds
链接答案中的代码做了类似的事情,但它更复杂,因为它假设__init__
本身需要await
。如果不是这种情况,并且您的 __init__
实际上是微不足道的,但您希望返回的实例是可等待的,则不需要拆分初始化的额外复杂性。
注意:尽管是recommended,asyncio.run()
仍被标记为临时的。在上面的例子中,它可以很容易地替换为run_until_complete
。
【讨论】:
我会玩这个。谢谢 @FedericoCorazza 对被拒绝的编辑感到抱歉,我不知道它是由提出问题的同一个人完成的。我现在修改了答案,提到了asyncio.run
的临时状态。以上是关于异步初始化时将参数传递给python类的主要内容,如果未能解决你的问题,请参考以下文章