在Python中有一种方法来检查一个函数是否是一个“生成器函数”之前调用它?

可以说我有两个function:

def foo(): return 'foo' def bar(): yield 'bar' 

第一个是正常的function,第二个是发电机function。 现在我想写这样的东西:

 def run(func): if is_generator_function(func): gen = func() gen.next() #... run the generator ... else: func() 

什么是is_generator_function()的简单实现? 使用types包我可以testinggen是否是一个生成器,但是我希望在调用func()之前这样做。

现在考虑下面的情况:

 def goo(): if False: yield else: return 

调用goo()将返回一个生成器。 我认为pythonparsing器知道goo()函数有一个yield语句,我想知道是否可以轻松地获取这些信息。

谢谢!

 >>> import inspect >>> >>> def foo(): ... return 'foo' ... >>> def bar(): ... yield 'bar' ... >>> print inspect.isgeneratorfunction(foo) False >>> print inspect.isgeneratorfunction(bar) True 
  • Python版本2.6中的新增内容

其实,我想知道这样一个假设的is_generator_function()是多么有用。 考虑:

 def foo(): return 'foo' def bar(): yield 'bar' def baz(): return bar() def quux(b): if b: return foo() else: return bar() 

什么应该is_generator_function()返回quuxquuxbaz()返回一个生成器,但不是一个本身,而且quux()可能返回一个生成器或者可能不会。

 >>> def foo(): ... return 'foo' ... >>> def bar(): ... yield 'bar' ... >>> import dis >>> dis.dis(foo) 2 0 LOAD_CONST 1 ('foo') 3 RETURN_VALUE >>> dis.dis(bar) 2 0 LOAD_CONST 1 ('bar') 3 YIELD_VALUE 4 POP_TOP 5 LOAD_CONST 0 (None) 8 RETURN_VALUE >>> 

正如你所看到的,关键的区别是bar的字节码将至less包含一个YIELD_VALUE操作码。 我build议使用dis模块(当然,将其输出redirect到一个StringIO实例并检查它的getvalue ),因为这提供了一个对字节码更改的健壮性度量 – 操作码的确切数值将会改变,但反汇编的符号值将保持相当稳定;-)。

我已经实现了装饰函数返回/产值的装饰器。 其基本原理是:

 import types def output(notifier): def decorator(f): def wrapped(*args, **kwargs): r = f(*args, **kwargs) if type(r) is types.GeneratorType: for item in r: # do something yield item else: # do something return r return decorator 

它的工作原理是因为装饰器函数是非空的调用的:它是被testing的返回值。


编辑:继罗伯特·卢霍评论后,我结束了这样的事情:

 def middleman(f): def return_result(r): return r def yield_result(r): for i in r: yield i def decorator(*a, **kwa): if inspect.isgeneratorfunction(f): return yield_result(f(*a, **kwa)) else: return return_result(f(*a, **kwa)) return decorator