首页 > 解决方案 > 类协程的一部分不是协程。为什么?

问题描述

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???

我需要找到一种方法将类中的协程包装成部分,以便结果也是一个协程。我怎么做?

标签: pythonpython-3.xpython-asyncio

解决方案


为什么是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然后在它从,解包 if 之后isfunction返回,False因为它只是那里的绑定方法。

这就是为什么。我不知道这是否可以被认为是一个错误,或者它是否是设计使然。_has_code_flag文档字符串在其描述中省略了包装方法这一事实functools.partial使我相信它是设计使然。

但是,您可以通过检查属性借用functools._unwrap_partial并使用他们检查 a 的方法。coroutine.func

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)

推荐阅读