Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 测试函数或方法是正常的还是异步的_Python_Python 3.x_Asynchronous_Python 3.5_Coroutine - Fatal编程技术网

Python 测试函数或方法是正常的还是异步的

Python 测试函数或方法是正常的还是异步的,python,python-3.x,asynchronous,python-3.5,coroutine,Python,Python 3.x,Asynchronous,Python 3.5,Coroutine,如何确定函数或方法是普通函数还是异步函数?我希望我的代码能够自动支持正常或异步回调,并且需要一种方法来测试传递的函数类型 async def exampleAsyncCb(): pass def exampleNomralCb(): pass def isAsync(someFunc): #do cool dynamic python stuff on the function return True/False async def callCallback

如何确定函数或方法是普通函数还是异步函数?我希望我的代码能够自动支持正常或异步回调,并且需要一种方法来测试传递的函数类型

async def exampleAsyncCb():
    pass

def exampleNomralCb():
    pass

def isAsync(someFunc):
    #do cool dynamic python stuff on the function
    return True/False

async def callCallback(cb, arg):
    if isAsync(cb):
        await cb(arg)
    else:
        cb(arg)
根据传递的函数类型,它应该正常运行,或者使用wait。我尝试了各种方法,但不知道如何使用Python模块实现
isAsync()

inspect.iscoroutinefunction(对象)

如果对象是协程函数(使用异步定义语法定义的函数),则返回true

此函数从Python 3.5开始就可用。 该模块适用于Python 2,功能较少,当然没有您想要的模块:

顾名思义,Inspect模块对于检查很多事情都很有用。文件上说

inspect模块提供了几个有用的函数来帮助获取有关活动对象的信息,例如模块、类、方法、函数、回溯、帧对象和代码对象。例如,它可以帮助您检查类的内容、检索方法的源代码、提取函数的参数列表并设置其格式,或者获取显示详细回溯所需的所有信息

该模块提供四种主要服务:类型检查、获取源代码、检查类和函数以及检查解释器堆栈

本模块的一些基本功能包括:

inspect.ismodule(object)
inspect.isclass(object)
inspect.ismethod(object)
inspect.isfunction(object)
它还具有检索源代码的功能

inspect.getdoc(object)
inspect.getcomments(object)
inspect.getfile(object) 
inspect.getmodule(object)

方法的命名直观。如有需要,可在文档中找到说明。

协同例程设置了
协同程序
标志,代码标志中的第7位:

>>> async def foo(): pass
>>> foo.__code__.co_flags & (1 << 7)
128   # not 0, so the flag is set.
政府正是这样做的;测试对象是否是函数或方法(以确保存在
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。看

当然,使用
inspect.iscoroutinefunction()
是最具可读性的,并且保证在代码标志发生更改时继续工作:

>>> inspect.iscoroutinefunction(foo)
True

如果您不想使用
inspect
引入另一个导入,那么
iscoroutine
也可在
asyncio
中使用

import asyncio

def isAsync(someFunc):
    return asyncio.iscoroutinefunction(someFunc)
TLDR

如果您想检查应该与
wait
一起使用的内容,请使用
inspect.isawaitable
(就像您测试的内容是
callable()
而不仅仅是一个函数)

iscoroutine
iscoroutinefunction
不同,它还适用于
未来的
s和实现
\uuuu wait\uuu
方法的对象


详细信息

当您传递协程函数时,上述解决方案将适用于简单情况。在某些情况下,您可能希望传递可等待的对象函数,该函数的行为类似于协程函数,但不是协程函数。两个例子是类或类似未来的对象类(类
\uuuuu wait\uuuu
magic方法)。在这种情况下,
iscoroutinefunction
将返回
False
,这是您不需要的

在非异步示例中,将非可调用函数作为回调传递更容易理解:

class SmartCallback:
    def __init__(self):
        print('SmartCallback is not function, but can be used as function')

callCallback(SmartCallback)  # Should work, right?
回到异步世界,类似的情况如下:

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)  # Should work, but oops! iscoroutinefunction(AsyncSmartCallback) == False
解决此问题的方法不是使用
iscoroutine
iscoroutinefunction
,而是使用
inspect.isawaitable
。它与就绪对象一起工作,所以您必须首先创建它。换句话说,我建议使用以下解决方案:

async def callCallback(cb, arg):
    if callable(cb):
        res = cb()  # here's result of regular func or awaitable
        if inspect.isawaitable(res):
            res = await res  # await if awaitable
        return res  # return final result
    else:
        raise ValueError('cb is not callable')

这是一个更通用的解决方案(我相信逻辑上是正确的)。

但是如果一个普通函数作为回调传递,恰好返回一个可等待的对象,那么这个行为不会改变吗?在这种情况下,返回的对象也会被等待/执行。类似于
def testcb():返回asynchSmartCallback
@Ecko,以防您通过此
testcb
,您得到的结果应该是
asynchSmartCallback
,不会等待任何结果。之所以发生这种情况,是因为
AsyncSmartCallback
不是可等待的对象,而是返回可等待对象的类:
AsyncSmartCallback()
-这是可等待的对象。如果函数
def testcb():return asynchSmartCallback()
,则将等待此对象。但是我看不出有什么问题:假设您传递
def testcb():return Callback()
——在这种情况下,也会执行
Callback()
。我喜欢最后的可调用选项。第二个也可以写在一个函数中,作为
def\uuuuu wait\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuself:return(从asyncio.sleep(1)中产生)。\uuuuu wait\uuuuuuuuuuuuuuuuuu。假设OP理解它,不会通过长时间运行的同步回调。但是。。。但是
True/False
除以
0
!:OIs在
inspect.iscoroutinefunction()
asyncio.iscoroutinefunction()
?@M.I.Wright之间有实际区别吗?不,没有。基于Python 3.6的源代码,
asyncio
版本只是从
inspect
模块重新导入的一个版本。@AlesTeska我没有查看源代码,但py3.7文档有一个说明,表明它们有细微的不同,特别是:
此方法不同于inspect.iscoroutinefunction()因为对于以@coroutine修饰的基于生成器的协程函数,它返回True。
好答案-两个建议:1)提及
inspect.isawaitable
,就像其他答案中的一个一样-它检查稍有不同的事情,但涵盖某些其他情况,并注意权衡会得到更全面的答案,2)关于Python2后端端口的旁白可能应该扩展为注意Python2中甚至不存在
async
/
await
,或者完全忽略。@hallo它们不相同,请参见:
与inspect.iscorou不同
async def callCallback(cb, arg):
    if callable(cb):
        res = cb()  # here's result of regular func or awaitable
        if inspect.isawaitable(res):
            res = await res  # await if awaitable
        return res  # return final result
    else:
        raise ValueError('cb is not callable')