TLDR
Use inspect.isawaitable
to check if an object should be used with await
. Unlike iscoroutine
or iscoroutinefunction
, it also works for Future
s and objects that implement the __await__
method.
Detailed
The previously mentioned solutions work well for simple cases where you pass a coroutine function. However, in some cases, you may want to pass an awaitable object function that behaves like a coroutine function but is not one. Two examples of this are the Future class or a Future-like object class (a class that implements the __await__
magic method). In these cases, using iscoroutinefunction
will return False
, which is not what you need.
This can be easier to understand with a non-async example of passing a non-function callable as a callback:
class SmartCallback:
def __init__(self):
print('SmartCallback is not function, but can be used as function')
callCallback(SmartCallback)
回到异步世界,情况类似:
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)
解决此问题的方法不是使用iscoroutine
或iscoroutinefunction
,而是使用inspect.isawaitable
。它可以处理已就绪的对象,因此您必须首先创建它。换句话说,我建议使用的解决方案是:
async def callCallback(cb, arg):
if callable(cb):
res = cb()
if inspect.isawaitable(res):
res = await res
return res
else:
raise ValueError('cb is not callable')
这是更普遍的(我相信也是逻辑上正确的)解决方案。
True/False
正在除以0! :O - Shadow