首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类协程的部分不是协程。为什么?

类协程的部分不是协程。为什么?
EN

Stack Overflow用户
提问于 2021-04-09 19:51:29
回答 2查看 321关注 0票数 7
代码语言:javascript
复制
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???

我需要找到一种方法来将类中的协程包装成partial,这样结果也是协程。我该怎么做?

EN

回答 2

Stack Overflow用户

发布于 2021-04-09 21:36:58

原因就是inspect module检查此问题的方式。

代码语言:javascript
复制
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_flagdefinition

代码语言:javascript
复制
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属性(包含function对象),然后,解开partial。最后,如果结果不是函数,则返回False,否则返回对底层函数的__code__属性进行标志检查的结果。

问题是while ismethod(f)什么也不做,因为在这一点上它仍然是partial对象。然后,在从partial中展开if之后,isfunction返回False,因为它只是一个绑定的方法。

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

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

代码语言:javascript
复制
def _unwrap_partial(func):
    while isinstance(func, partial):
        func = func.func
    return func

摘自this answer

代码语言:javascript
复制
def iscoroutinefunction_or_partial(object):
    while isinstance(object, functools.partial):
        object = object.func
    return inspect.iscoroutinefunction(object)
票数 6
EN

Stack Overflow用户

发布于 2021-04-12 18:44:22

根据您的comment,您需要创建一个协程:

代码语言:javascript
复制
def async_partial(async_fn, *args):
    async def wrapped():
        return await async_fn(*args)
    return wrapped

foo1 = async_partial(Foo().foo, 1)
assert inspect.iscoroutinefunction(foo1)
assert asyncio.run(foo1()) == 1

这与“真正的”functools.partial之间的区别在于后者返回的callable可以被多次调用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67020609

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档