creating generators from function

Peter Otten __peter__ at web.de
Wed Dec 8 05:54:42 EST 2004


Simon Wittber wrote:

> I use a coroutine/generator framework for simulating concurrent processes.
> 
> To do this, I write all my functions using the general form:
> 
> while True:
> do stuff
> yield None
> 
> To make these generator functions compatible with a standard thread
> interface, I attempted to write a decorator which converts a standard
> function into a generator function (code attached below).
> Unfortunately, I received an exception, before I could test if my idea
> would work:
> 
> TypeError: cannot create 'generator' instances
> 
> I guess I can go the other way, and convert a generator into a
> function, but that just doesn't seem right.
> 
> Is there anyway solve the problem described?
 
Generators are just functions with an extra flag set. I tried the following
modification of your code:

<code>
from opcode import opmap
globals().update(opmap)

def _f(): pass
function = type(_f)
del _f

def generatorize(f):
    co = f.func_code
    nc = [ord(x) for x in co.co_code]
    for i, op in enumerate(nc[:-1]):
        if op == RETURN_VALUE:
            nc[i] = YIELD_VALUE
    newcode = ''.join([chr(x) for x in nc])
    
    codeobj = type(co)(co.co_argcount, co.co_nlocals, co.co_stacksize,
                        co.co_flags + 32, newcode, co.co_consts,
co.co_names,
                        co.co_varnames, co.co_filename, co.co_name,
                        co.co_firstlineno, co.co_lnotab, co.co_freevars,
                        co.co_cellvars)
    
    return function(codeobj, f.func_globals, f.func_name,
        f.func_defaults, f.func_closure)

@generatorize
def f():
    while True:
        return 1

def g():
    while True:
        yield 1

print g()
print f()

import itertools
print list(itertools.islice(f(), 5))
</code>

The hardest part was to find the enumerate() bug. I agree with Steven that
converting between functions and generators by replacing return with yield
and vice versa is hardly ever useful, though.

Peter















More information about the Python-list mailing list