Here is an suggestion using a proxy.
def selfDecorator(func):
def wrap(*args, **kw):
return SelfGenerator(func, args, kw)
return wrap
class SelfGenerator(object):
"""This class implements the generator interface"""
def __init__(self, generator, args, kw):
self.generator = generator(self, *args, **kw)
def __iter__(self):
return self
def __next__(self):
return next(self.generator)
next = __next__
def send(self, value):
return self.generator.send(value)
@selfDecorator
def gen(self, x): # your generator function with self
for i in range(x):
yield self
for x in gen(5):
print x # prints <__main__.SelfGenerator object at 0x02BB16D0>
Since SelfGenerator
is a proxy to the original generator it has the same interface and can be used totally as the Pythons own generator.
First Answer
You can not call a generator in itself:
>>> def generator():
for value in g:
yield value
>>> g = generator()
>>> next(g)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
next(g)
File "<pyshell#11>", line 2, in generator
for value in g:
ValueError: generator already executing
Guessing: The self in the paper may not mean the generator itself but an object, some state holder that maybe is shared between some generators.
More precisely, the directed graph of constraints is required to be cycle-free when it is regarded as an undirected graph.
This makes me think that the generator does not refer to its 'identical' execution. Why should it get its own value out of itself by iterating? It can use a local variable.
Coroutines originate from Simula. Maybe to understand what the self is you can have a look at the language.