2016-03-18 3 views
15

関数またはメソッドが通常関数または非同期関数であるかどうか調べるにはどうすればよいですか?私のコードでは、通常のコールバックまたは非同期のコールバックを自動的にサポートし、どのタイプの関数が渡されるかをテストする方法が必要です。関数またはメソッドが正常または非同期であるかどうかのテスト

async def exampleAsyncCb(): 
    pass 

def exampleNomralCb(): 
    pass 

def isAsync(someFunc): 
    #do cool dynamic python stuff on the function 
    return True/False 

async def callCallback(cb, arg): 
    if isAsync(cb): 
     await cb(arg) 
    else: 
     cb(arg) 

そして、それが正常にまたはのawaitでそれを実行する必要がありますいずれか渡さ機能の種類によって異なります。私は様々なことを試しましたが、どのように実装するのか分かりませんisAsync()

+0

しかし、「真/偽​​」は「0」で割っています! :O – Shadow

答えて

16

Pythonのinspectモジュールを使用してください。

inspect.iscoroutinefunction(object)

戻る真の目的は、コルーチン関数(非同期DEF構文で定義された関数)である場合。

この関数は、Python 3.5以降で使用できます。 このモジュールは、Python 2の機能が少なく、探しているモジュールがなくても利用できます。inspect

名前が示すようにモジュールを検査すると、多くのことを調べるのに便利です。ドキュメントは

言う検査モジュールは、モジュール、クラス、メソッド、関数・トレースバック・フレームオブジェクト・コードオブジェクトなどのオブジェクトに関する情報を得るのを助けるために、いくつかの便利な機能を提供します。たとえば、クラスの内容を調べたり、メソッドのソースコードを取得したり、関数の引数リストを抽出してフォーマットしたり、詳細なトレースバックを表示するのに必要なすべての情報を取得するのに役立ちます。

このモジュールで提供される主なサービスには、型チェック、ソースコードの取得、クラスと関数の検査、インタープリタスタックの検査があります。

このモジュールのいくつかの基本的な機能は以下のとおりです。

inspect.ismodule(object) 
inspect.isclass(object) 
inspect.ismethod(object) 
inspect.isfunction(object) 

また

inspect.getdoc(object) 
inspect.getcomments(object) 
inspect.getfile(object) 
inspect.getmodule(object) 

方法が直感的に命名されているソースコードを取得する機能をパックします。必要に応じて説明がドキュメントにあります。

+0

'inspect.iscoroutinefunction()'と 'asyncio.iscoroutinefunction()'の間には実用的な違いがありますか? –

11

コルーチンは、COROUTINEフラグが設定されている、コードフラグのビット6:

値128が inspectモジュールに定数として記憶される
>>> async def foo(): pass 
>>> foo.__code__.co_flags & (2 << 6) 
128 # not 0, so the flag is set. 

>>> import inspect 
>>> inspect.CO_COROUTINE 
128 
>>> foo.__code__.co_flags & inspect.CO_COROUTINE 
128 

inspect.iscoroutinefunction() functionはありませんそれだけ;オブジェクトがファンクションまたはメソッドであるかどうかをテストし(__code__属性があることを確認する)、そのフラグをテストします。 source codeを参照してください。もちろん

inspect.iscoroutinefunction()を使用すると、最も読みやすいですし、これまでのコードフラグを変更した場合は動作し続けることが保証:さ

>>> inspect.iscoroutinefunction(foo) 
True 
+0

ソースレベルの洞察力を提供していただき、ありがとうございます。 – Sharad

14

をあなたはinspectで別のインポートを導入したくない場合は、iscoroutineasyncioでもご利用いただけます。

import asyncio 

def isAsync(someFunc): 
    return asyncio.iscoroutinefunction(someFunc) 
+0

'asyncio.iscoroutinefunction()'関数は* 2回のテストを行います。最初に 'inspect.iscoroutinefunction()'を使用し、その関数が '' @acyncio.coroutine'デコレータを持つ関数であるかどうかテストが失敗した場合(https://docs.python.org/3/library/asyncio) -task.html#asyncio.coroutine)が適用されます。これを考慮に入れてください! –

3

上記のソリューションは、コルーチン関数を渡すと単純なケースで動作します。場合によっては、待遇オブジェクト関数をコルーチン関数のように動作させるが、コルーチン関数ではない関数に渡すことがあります。 2つの例は、Futureクラスまたはフューチャーのようなオブジェクトクラス(クラスはimplements__await__の魔法)です。この場合、iscoroutinefunctionFalseを返します。何が必要なのでしょうか?

それはコールバックとして非機能呼び出し可能なパッシングと非非同期例に理解することは簡単です:、

class SmartCallback: 
    def __init__(self): 
     print('SmartCallback is not function, but can be used as function') 

await callCallback(SmartCallback) # Should work, right? 

戻る非同期の世界に似たような状況:それをしませ解決する

class AsyncSmartCallback: 
    def __await__(self): 
     return self._coro().__await__() 

    async def _coro(self): 
     print('AsyncSmartCallback is not coroutine function, but can be used as coroutine function') 
     await asyncio.sleep(1) 

await callCallback(AsyncSmartCallback) # Should work, but oops! iscoroutinefunction(AsyncSmartCallback) == False 

ウェイiscoroutineまたはiscoroutinefunctionを使用しますが、代わりにinspect.isawaitableを使用してください。準備ができているオブジェクトで動作するので、最初に作成する必要があります。言い換えれば、ソリューションを使用することをお勧めします:

async def callCallback(cb, arg): 
    if callable(cb): 
     res = cb() # here's result of regular func or awaitable 
     if inspect.isawaitable(res): 
      res = await res # await if awaitable 
     return res # return final result 
    else: 
     raise ValueError('cb is not callable') 

これはより普遍的な(と私は確かに論理的に正しい)ソリューションです。

+0

しかし、通常の関数がコールバックとして渡されて待っているオブジェクトが返された場合、その動作が変更されません。この場合、返されたオブジェクトも待っている/実行されます。 'def testcb()のように:return AsyncSmartCallback' – Ecko

+0

@Eckoこの' testcb'を渡す場合には、 'AsyncSmartCallback'があるはずですが、何も待たれることはありません。これは 'AsyncSmartCallback'が待ち時間のないオブジェクトであるため、待ち受け可能なオブジェクトを返すクラスです:' AsyncSmartCallback() ' - これは待ち受け可能なオブジェクトです。あなたの関数 'def testcb():return AsyncSmartCallback()'の場合、このオブジェクトは待たれるでしょう。しかし、何も間違っているとは思えません。あなたが 'def testcb():return Callback()'を渡したとすると、 'Callback()'も実行されます。 –

関連する問題