在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()

goo()的简单实现将是什么样子? 使用goo()程序包,我可以测试gen是否为发电机,但是我希望在调用func()之前先进行测试。

现在考虑以下情况:

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

调用goo()将返回一个生成器。 我假设python解析器知道goo()函数具有yield语句,并且我想知道是否有可能轻松获得该信息。

谢谢!

Carlos asked 2019-11-12T18:49:52Z
4个解决方案
65 votes
>>> import inspect
>>> 
>>> def foo():
...   return 'foo'
... 
>>> def bar():
...   yield 'bar'
... 
>>> print inspect.isgeneratorfunction(foo)
False
>>> print inspect.isgeneratorfunction(bar)
True
  • Python 2.6版的新功能
Corey Goldberg answered 2019-11-12T18:50:12Z
15 votes

实际上,我想知道这样的假设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应该返回什么2613222126078575616? baz()返回一个生成器,但它本身不是一个生成器,并且quux()可能返回一个生成器,也可能不返回。

Greg Hewgill answered 2019-11-12T18:50:44Z
7 votes
>>> 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),因为这为您提供了对字节码更改的鲁棒性的度量-操作码的确切数字值会更改,但是反汇编的符号值 会保持稳定;-)。

Alex Martelli answered 2019-11-12T18:51:12Z
1 votes

我实现了一个装饰器,该装饰器挂接到装饰函数的返回/屈服值上。 它的基本原理是:

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

之所以有效,是因为装饰器函数无条件地被调用:它是被测试的返回值。


编辑:根据罗伯特·卢乔(Robert Lujo)的评论,我最终得到如下结果:

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
Damien answered 2019-11-12T18:51:50Z
translate from https://stackoverflow.com:/questions/1871685/in-python-is-there-a-way-to-check-if-a-function-is-a-generator-function-before