在python中有一种方法可以在调用之前检查函数是否是"生成器函数"?

Car*_*los 57 python function generator coroutine

可以说我有两个功能:

def foo():
  return 'foo'

def bar():
  yield 'bar'
Run Code Online (Sandbox Code Playgroud)

第一个是正常函数,第二个是生成器函数.现在我想写这样的东西:

def run(func):
  if is_generator_function(func):
     gen = func()
     gen.next()
     #... run the generator ...
  else:
     func()
Run Code Online (Sandbox Code Playgroud)

什么是直截了当的实现is_generator_function()?使用types包我可以测试是否 gen是生成器,但我希望在调用之前这样做func().

现在考虑以下情况:

def goo():
  if False:
     yield
  else:
     return
Run Code Online (Sandbox Code Playgroud)

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

谢谢!

Cor*_*erg 65

>>> import inspect
>>> 
>>> def foo():
...   return 'foo'
... 
>>> def bar():
...   yield 'bar'
... 
>>> print inspect.isgeneratorfunction(foo)
False
>>> print inspect.isgeneratorfunction(bar)
True
Run Code Online (Sandbox Code Playgroud)
  • Python 2.6版中的新功能

  • 只是2014年的评论,感谢您提供2009年问题的2011年答案:) (36认同)
  • 以为这解决了我的问题,但并不完美.如果函数是包装的生成器,例如`partial(generator_fn,somearg = somevalue)`那么这将不会被检测到.lambda也不会在类似的情况下使用,例如`lambda x:generator_fun(x,somearg = somevalue)`.这些实际上按预期工作; 他的代码正在尝试一个可以链接生成器的辅助函数,但是如果找到一个正常的函数,它会将它包装在"单项生成器"中. (3认同)
  • 只是 2020 年的评论,感谢您在 2014 年感谢他就 2009 年的问题提供了 2011 年的答案。 (2认同)

Gre*_*ill 15

实际上,我想知道这样一个假设是多么有用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()
Run Code Online (Sandbox Code Playgroud)

我应该is_generator_function()返回bazquuxbaz()返回一个生成器但不是一个生成器,quux()可能会返回一个生成器,也可能不返回.

  • 分别是假,真,假,假.它不是关于函数是否返回生成器实例,而是关于它是否是生成器函数! (12认同)

Ale*_*lli 7

>>> 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        
>>> 
Run Code Online (Sandbox Code Playgroud)

如您所见,关键区别在于字节码bar将包含至少一个YIELD_VALUE操作码.我建议使用该dis模块(当然,将其输出重定向到StringIO实例并检查它getvalue),因为这为您提供了字节码更改的稳健性测量 - 操作码的确切数值将会改变,但反汇编的符号值将保持不变相当稳定;-).