我对asthonio for python 3.6
非常陌生所以问题是我有一个类,我想在那里初始化一些属性。 其中一个属性是异步函数的返回值。
这样做的最佳做法是什么?
在init函数中调用event_loop一次以获取返回值?
使__init__函数异步?并在事件循环中运行它?
干杯!
再次更新:以下是我的代码:
import asyncio
import aioredis
from datetime import datetime
class C:
def __init__(self):
self.a = 1
self.b = 2
self.r = None
asyncio.get_event_loop().run_until_complete(self._async_init())
async def _async_init(self):
# this is the property I want, which returns from an async function
self.r = await aioredis.create_redis('redis://localhost:6379')
async def heart_beat(self):
while True:
await self.r.publish('test_channel', datetime.now().__str__())
await asyncio.sleep(10)
def run(self):
asyncio.get_event_loop().run_until_complete(self.heart_beat())
c=C()
c.run()
答案 0 :(得分:4)
在init函数中调用event_loop一次以获取返回值?
如果在__init__
期间旋转事件循环,则在事件循环运行时您无法实例化C
; asyncio事件循环don't nest。
[编辑:在对问题进行第二次更新后,事件循环似乎由非静态方法C.run
运行,因此run_until_complete
位于{{ 1}}将使用编写的代码。但是这种设计是有限的 - 例如,当事件循环运行时,它不允许构建 __init__
的另一个实例或类似C
的类。] < / p>
如果不诉诸非常丑陋的黑客,使
C
函数异步?并在事件循环中运行它?
__init__
就无法变得异步。 Python的__init__
由副作用操作,必须返回__init__
,而None
函数返回一个协程对象。
为了完成这项工作,您有以下几种选择:
async def
工厂创建一个返回C
个实例的异步函数,例如:
C
这样的函数可以没有问题地异步,并且可以根据需要等待。如果您更喜欢静态方法到函数,或者如果您觉得从类中未定义的函数访问私有方法感到不舒服,可以将async def make_c():
c = C()
await c._async_init()
return c
替换为make_c()
。
C.create()
字段您可以使C.r
属性异步,只需在其中存储r
:
Future
这需要将<{>每个使用class C:
def __init__(self):
self.a = 1
self.b = 2
loop = asyncio.get_event_loop()
# note: no `await` here: `r` holds an asyncio Task which will
# be awaited (and its value accessed when ready) as `await c.r`
self.r = loop.create_task(aioredis.create_redis('redis://localhost:6379'))
拼写为c.r
。这是否可接受(甚至是有益的)取决于程序中其他地方使用的位置和频率。
await c.r
构造函数虽然C
无法变为异步,但此限制并不适用于其低级表兄__init__
。 __new__
可以返回任何对象,包括一个甚至不是T.__new__
实例的对象,我们可以使用它来返回一个协程对象:
T
除非你有充分的理由使用它,否则最后一种方法是我不建议用于生产代码的。
class C:
async def __new__(cls):
self = super().__new__(cls)
self.a = 1
self.b = 2
self.r = await aioredis.create_redis('redis://localhost:6379')
return self
# usage from another coroutine
async def main():
c = await C()
# usage from outside the event loop
c = loop.run_until_complete(C())
构造函数,它不会返回C.__new__
实例; C
; C.__init__
看起来非惯用,甚至(尤其)对于曾经使用asyncio的人来说。