如何检查一个Python函数是否为Tornado生成器

4

如何检查函数 foobar 是否是 Tornado 所需的生成器?

In [1]: from tornado import gen

In [2]: @gen.coroutine
   ...: def foobar():
   ...:     print 'boom'
   ...:

我无法找到任何属性,表明它被一个gen.coroutine正确装饰了。


也许在 foobar.func_code.co_filename 中。 - wim
然后在其中搜索单词“gen”?看起来有些hacky,但比我找到的其他任何东西都更接近。 - Mikhail
看起来非常不专业和糟糕,这就是为什么我评论而不是回答的原因。但是在Python2中我找不到更好的解决方法。 - wim
1
'TracebackFuture' in foobar.func_code.co_names 还是有点瑕疵,但更接近于完美。 - Mikhail
2个回答

4

目前还没有很好的方法来检测这个问题,即使将@coroutine修改为设置某些属性,在使用多个装饰器(例如处理程序可能同时使用@authenticated@coroutine装饰器,而@authenticated装饰器的包装将隐藏@coroutine添加的任何内容)的情况下,这种方法也会失败。

此外,许多函数(包括核心Tornado方法,如AsyncHTTPClient.fetchIOStream的大多数方法)在技术上并不是协程,但可以像协程一样调用。在大多数情况下,最重要的问题不是“这是一个协程吗”,而是“它是否返回一个Future”。在Python中没有办法在不调用函数的情况下确定这一点。


最终我自己编写了一个装饰器,用tornado的协程修饰了函数,并添加了一个标志以供检查。虽然不是理想的解决方案,但它为我提供了一种在执行函数之前对传递的函数进行各种合理性检查的方法。 - Mikhail

2

我无法找到一种令人满意的方式来自现有的装饰器gen.coroutine内省它。

如果您对具体的装饰器有控制权,那么您可以选择简单地向函数本身附加属性,这可能对您有所帮助。

>>> def my_gen_coroutine(f):
...     f = gen.coroutine(f)
...     f.is_a_tornado_generator = True
...     return f
... 
>>> @my_gen_coroutine
... def foobar():
...     print 'boom'
...     
>>> foobar.is_a_tornado_generator
True
>>> foobar()
boom
<tornado.concurrent.Future at 0x1397d50>

当你不确定属性是否存在时,可以使用getattr(some_function, 'is_a_tornado_generator', False)


:( 是啊,但我不想要求我的库的用户使用自定义装饰器...尽管从我在网上搜索的结果来看,这似乎是最可行的解决方案。 - Mikhail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接