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,这样结果也是协程。我该怎么做?
发布于 2021-04-09 21:36:58
原因就是inspect module检查此问题的方式。
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的definition
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。
def _unwrap_partial(func):
while isinstance(func, partial):
func = func.func
return funcdef iscoroutinefunction_or_partial(object):
while isinstance(object, functools.partial):
object = object.func
return inspect.iscoroutinefunction(object)发布于 2021-04-12 18:44:22
根据您的comment,您需要创建一个协程:
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可以被多次调用。
https://stackoverflow.com/questions/67020609
复制相似问题