How can I find out if a function or method is a normal function or an async function? I would like my code to automatically support normal or async callbacks and need a way to test what type of function is passed.
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)
And depending on what type of function gets passed it should either run it normally or with await. I tried various things but have no idea how to implement isAsync()
.
Use the inspect module of Python.
inspect.iscoroutinefunction(object)
This function is available since Python 3.5. The module is available for Python 2 with lesser functionalities and certainly without the one you are looking for: inspect
Inspect module as the name suggests is useful to inspect a whole lot of thing. The documentation says
Some basic capabilities of this module are:
It also packs capability to retrieve the source code
Methods are named intuitively. Description if needed can be found in documentation.
If you don't want to introduce another import with
inspect
,iscoroutine
is also available insideasyncio
.Co-routines have the
COROUTINE
flag set, bit 6 in the code flags:The value 128 is stored as a constant in the
inspect
module:The
inspect.iscoroutinefunction()
function does just that; test if the object is a function or method (to ensure there is a__code__
attribute) and test for that flag. See the source code.Of course, using
inspect.iscoroutinefunction()
is the most readable and guaranteed to continue to work if ever the code flags were to change:TLDR
If you want to check something should be used with
await
, useinspect.isawaitable
(as when you test something beingcallable()
other than just being a function).Unlike
iscoroutine
oriscoroutinefunction
it will also work forFuture
s and objects that implement__await__
method.Solutions above will work for simple cases, when you pass coroutine function. In some cases you may like to pass awaitable object function that acts like coroutine function, but is not coroutine function. Two examples is Future class or Future-like object class (class that implements
__await__
magic method). In this casesiscoroutinefunction
will returnFalse
, what is not you need.It's easier to understand on non-async example with passing non-function callable as callback:
Back to async world, a similar situation:
Way to solve it not to use
iscoroutine
oriscoroutinefunction
, but useinspect.isawaitable
instead. It works with ready object so you must create it first. In other words, solution I would advise to use:It's more universal (and I'm sure logically correct) solution.