在python中有一种方法可以在调用它之前检查函数是否是“生成器函数”?
可以说我有两个功能:在python中有一种方法可以在调用它之前检查函数是否是“生成器函数”?
def foo():
return 'foo'
def bar():
yield 'bar'
第一个是一个正常的功能,第二个是发电机功能。现在,我想写的东西是这样的:
def run(func):
if is_generator_function(func):
gen = func()
gen.next()
#... run the generator ...
else:
func()
什么会直接实现的is_generator_function()
样子?使用types
软件包,我可以测试gen
是否为发生器,但我希望在调用func()
之前这样做。
现在考虑以下情况:
def goo():
if False:
yield
else:
return
的goo()
的调用将返回一个发电机。我认为Python解析器知道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版本
只是2014年的一条评论,感谢你在2009年问题上提供2011年答案:) – wim 2014-03-14 02:07:19
认为这解决了我的问题,但它并不完美。如果函数是一个封装的生成器,比如'partial(generator_fn,somearg = somevalue)',那么这个不会被检测到。 lambda x:generator_fun(x,somearg = somevalue)'也不会在类似的情况下使用lambda。这些实际上按预期工作;他的代码正在试验一个可以链式生成器的辅助函数,但是如果找到了一个正常的函数,它会将它包装在一个“单个项目生成器”中。 – 2016-08-25 18:38:12
>>> 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
字节码将包含至少一个YIELD_VALUE
操作码。我推荐使用dis
模块(将其输出重定向到StringIO实例并检查其当前的getvalue
),因为这为您提供了对字节码更改的鲁棒性度量 - 操作码的确切数值将会改变,但反汇编的符号值将保持相当稳定;-)。
其实,我想知道这样一个假设的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()
回报baz
和quux
? baz()
返回一个发生器,但不是一个本身,并且quux()
可能会返回一个发生器或可能不会。
@Greg,绝对 - 任何可调用的函数都可以返回一个可迭代的(可能特别是迭代器和超特定的生成器,或者可能不会)或其他东西(或者根本不产生任何异常),取决于关于论点,随机数字或月球的相位。生成器函数是一个可调用的函数,如果“如果它返回任何东西而不是提高,将返回一个生成器对象”(同时,并不是所有符合条件的可调用函数都是gnerator函数)。用例因此难以调制。 – 2009-12-09 05:34:17
你说得对,这是一种假设的问题。它是在我阅读David Beazley关于协同程序的演示文稿时发布的:http://www.dabeaz.com/coroutines/ – Carlos 2009-12-09 05:36:34
分别是False,True,False,False。它不是关于函数是否返回生成器实例,而是关于它是否是生成器函数! – wim 2014-03-14 02:05:15
,我实现了对装饰函数的返回/产生价值钩子装饰。它的基本云:
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
它的工作原理,因为装饰功能unconditionnaly称为:这是测试的返回值。
编辑:继罗伯特·路约的评论,我结束了类似:
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
我有类似的情况,我得到了错误:SyntaxError:'返回'与发电机内的参数。当我想到它时,它看起来是合乎逻辑的,相同的功能在同一时间不能是正常的功能和发电机功能。这对你的情况真的有用吗? – 2015-09-03 16:04:52
值得注意的是有用的,如果一个函数包含'yield'声明,那么'回报'函数内的声明不允许有参数。它必须只是'返回',它终止了发电机。好问题! – 2009-12-09 05:13:29
好点,'goo()'不应该是有效的,但它至少在这里(Python 2.6.2)。 – Carlos 2009-12-09 05:32:02
给当前读者的一个说明:@GregHewgill上面的评论不再正确,现在你可以返回参数(它是在StopIteration的值attr处传递的) – wim 2014-03-14 01:58:40