类协程的一部分不是协程。为什么?
class Foo:
async def foo(self, a):
return a
async def bar(b):
return b
asyncio.iscoroutinefunction(functools.partial(bar, 1)) # returns True, OK
asyncio.iscoroutinefunction(functools.partial(Foo().foo, 1)) # returns False, WHY???
我需要找到一种方法将类中的协程包装成部分的,这样结果也是一个协程。我怎么做?
回答
为什么是inspect 模块检查这个的方式。
def iscoroutinefunction(obj):
"""Return true if the object is a coroutine function.
Coroutine functions are defined with "async def" syntax.
"""
return _has_code_flag(obj, CO_COROUTINE)
如果我们看一下定义为_has_code_flag:
def _has_code_flag(f, flag):
"""Return true if ``f`` is a function (or a method or functools.partial
wrapper wrapping a function) whose code object has the given ``flag``
set in its flags."""
while ismethod(f):
f = f.__func__
f = functools._unwrap_partial(f)
if not isfunction(f):
return False
return bool(f.__code__.co_flags & flag)
我们看到它首先尝试解包绑定方法并获取其.func属性(包含函数对象),然后解包partial. 最后,如果结果不是函数返回,False否则返回对底层函数__code__属性进行标志检查的结果。
问题是while ismethod(f)它什么都不做,因为那时它仍然是一个partial对象。然后解开后,如果从partial,isfunction回报率False,因为它仅仅是一个绑定的方法存在。
这就是为什么。我不知道这是否可以被视为错误,或者是否是设计使然。文档字符串在其描述中_has_code_flag遗漏了functools.partial包装方法这一事实让我相信这是设计使然。
但是,您可以借用functools._unwrap_partial并使用他们coroutine通过检查.func属性来检查a 的方法。
def _unwrap_partial(func):
while isinstance(func, partial):
func = func.func
return func
取自这个答案:
def iscoroutinefunction_or_partial(object):
while isinstance(object, functools.partial):
object = object.func
return inspect.iscoroutinefunction(object)