2016-10-28 4 views
3

私はコルーチン関数をデコレートし、コルーチンから返された値を将来のインスタンスに割り当てます。装飾されたコルーチンの単一イベントループを使用して将来の結果を返します

import asyncio 
import functools 


def ensure_prepare(future): 
    async def decorator(asyncfunc): 
     @functools.wraps(asyncfunc) 
     async def wrapper(*args, **kwargs): 
      future.set_result(await asyncfunc(*args, **kwargs)) 
      return future 
     return wrapper 
    return decorator 

デモ:

>>> future = asyncio.Future() 
>>> 
>>> @ensure_prepare(future) 
... async def check_sanity(): 
...  return 9 
... 
>>> loop = asyncio.get_event_loop() 
>>> loop.run_until_complete(check_sanity) 
<function check_sanity at 0x7f935300a158> 
>>> _() 
<coroutine object check_sanity at 0x7f934f78a728> 
>>> loop.run_until_complete(_) 
<Future finished result=9> 
>>> _.result() 
9 

あなたは、私は将来の結果を得るために2回のイベントループを実行する必要が見ることができるように。最初の実行後にイベントループが値を返すようにする方法はありますか? が私のコードでを待っていて、結果(機能)を名前に割り当てることは望ましくありません。あなたのコード内

+1

umなぜあなたは 'decorator'をasyncとして定義していますか?私はあなたが 'run_until_complete(chech_sanity)'を初めて実行するときに、ラッパーを構築するためにデコレータを実行していることを確信しています。あなたが 'def decorator'行から' async'を削除すると、あなたの問題は解決しますか? –

+0

これは興味深い質問です。あなたはデコレータ関数でコルーチンをラップしようとしています。コルーチンはそれらを待っている必要がありますので、あなたがそれを望んでいないと言ったときにあなたが何を意味するのか分かりません。あなたがしようとしていることを明確にすることができますか? – Keith

+0

@Keith私は並行処理を使っていくつかのIO処理をしていますが、ある時点では、すべてのタスクが完了するのを待ってから別のものに移動する必要があります。これを行うには、将来のオブジェクトをセンチネル(私はそれが良いアイディアかどうかはわかりません)として使用し、内側の 'decorator'関数をcoroutineとして定義しました。これがここの原因です。これはおそらく、金曜日に勤務時間後にそのようなことを行うべきであるという印です。 – styvane

答えて

1

あなたが望んだものではありませんどのasyncなるためにあなたのdecoratorラッパーを作っている、それはあなたがあなたのラッパーを使用するすべての時間はそれがラップ機能を生成しますコルーチンオブジェクトをバック与えることを意味します

>>> future = asyncio.Future() 
>>> @ensure_prepare(future) 
async def chech_sanity(): 
    return 9 

>>> check_sanity 
<coroutine object ensure_prepare.<locals>.decorator at 0x10572f4c0> 

>>> check_sanity.send(None) #advance coroutine 
Traceback (most recent call last): 
    File "<pyshell#7>", line 1, in <module> 
    check_sanity.send(None) #advance coroutine 
StopIteration: <function check_sanity at 0x105096a60> 

       #^the function is the result of the coroutine 

はこれだけライン

async def decorator(asyncfunc): 

asyncを削除して、あなたの問題が解決されます。

def ensure_prepare(future): 
    def decorator(asyncfunc): 
     @functools.wraps(asyncfunc) 
     async def wrapper(*args, **kwargs): 
      future.set_result(await asyncfunc(*args, **kwargs)) 
      return future 
     return wrapper 
    return decorator 


>>> future = asyncio.Future() 
>>> @ensure_prepare(future) 
async def check_sanity(): 
    return 9 

>>> chech_sanity 
<function check_sanity at 0x105784a60> 
>>> loop = asyncio.get_event_loop() 
>>> loop.run_until_complete(check_sanity()) #remember to call check_sanity! 
<Future finished result=9> 
関連する問題