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!
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.
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.
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.
>>> import inspect >>> >>> def foo(): ... return 'foo' ... >>> def bar(): ... yield 'bar' ... >>> print inspect.isgeneratorfunction(foo) False >>> print inspect.isgeneratorfunction(bar) True
>>> 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;-).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With