![](/img/trans.png)
[英]How to generalize a function call which may be async, tornado coroutine, or normal?
[英]Call an async function in an normal function
我对python 3.6的asyncio很新
所以问题是我有一个类,我想在那里初始化一些属性。 其中一个属性是异步函数的返回值。
这样做的最佳做法是什么?
在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()
在init函数中调用event_loop一次以获取返回值?
如果在__init__
期间旋转事件循环,则在事件循环运行时将无法实例化C
; asyncio事件循环不嵌套 。
[ 编辑:在问题的第二次更新之后,事件循环似乎由非静态方法C.run
,因此__init__
run_until_complete
将与编写的代码一起使用。 但是这种设计是有限的 - 例如,它不允许在事件循环运行时构造C
或类C
另一个实例。
使
__init__
函数异步? 并在事件循环中运行它?
如果不诉诸非常丑陋的黑客, __init__
不能异步。 Python的__init__
按副作用运行,必须返回None
,而async def
函数返回一个协程对象。
要使这项工作,你有几个选择:
C
工厂 创建一个返回C
实例的异步函数,例如:
async def make_c():
c = C()
await c._async_init()
return c
这样的函数可以没有问题地异步,并且可以根据需要等待。 如果您更喜欢静态方法到函数,或者如果您感觉不舒服从类中未定义的函数访问私有方法,则可以使用make_c()
替换C.create()
。
Cr
字段 你可以简单地通过在其中存储Future
来使r
属性异步:
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'))
这将要求每次使用cr
拼写为await cr
。 这是否可接受(或甚至是有益的)取决于程序中其他地方使用的位置和频率。
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
实例的C.__new__
构造函数; C.__init__
; await C()
看起来非惯用,甚至(或特别)对于习惯于asyncio的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.