在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()
返回quux
和quux
? baz()
返回一个生成器,但不是一个本身,而且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