Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In python is there a way to check if a function is a "generator function" before calling it?

Lets say I have two functions:

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

The first one is a normal function, and the second is a generator function. Now I want to write something like this:

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

What will a straightforward implementation of is_generator_function() look like? Using the types package I can test if gen is a generator, but I wish to do so before invoking func().

Now consider the following case:

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

An invocation of goo() will return a generator. I presume that the python parser knows that the goo() function has a yield statement, and I wonder if it possible to get that information easily.

Thanks!

like image 332
Carlos Avatar asked Dec 09 '09 05:12

Carlos


People also ask

How does Python know if a function is a generator?

Create Generators in Python If a function contains at least one yield statement (it may contain other yield or return statements), it becomes a generator function. Both yield and return will return some value from a function.

Which keyword tell the Python that function is generator in Python?

Generator-Function : A generator-function is defined like a normal function, but whenever it needs to generate a value, it does so with the yield keyword rather than return. If the body of a def contains yield, the function automatically becomes a generator function.

How do you access the generator object in Python?

You need to call next() or loop through the generator object to access the values produced by the generator expression. When there isn't the next value in the generator object, a StopIteration exception is thrown. A for loop can be used to iterate the generator object.


2 Answers

>>> import inspect >>>  >>> def foo(): ...   return 'foo' ...  >>> def bar(): ...   yield 'bar' ...  >>> print inspect.isgeneratorfunction(foo) False >>> print inspect.isgeneratorfunction(bar) True 
  • New in Python version 2.6
like image 79
Corey Goldberg Avatar answered Oct 13 '22 00:10

Corey Goldberg


>>> 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         >>>  

As you see, the key difference is that the bytecode for bar will contain at least one YIELD_VALUE opcode. I recommend using the dis module (redirecting its output to a StringIO instance and checking its getvalue, of course) because this provides you a measure of robustness over bytecode changes -- the exact numeric values of the opcodes will change, but the disassembled symbolic value will stay pretty stable;-).

like image 20
Alex Martelli Avatar answered Oct 12 '22 23:10

Alex Martelli