[Python-Dev] Simple generators, round 2

Samuele Pedroni pedroni@inf.ethz.ch
Sun, 18 Mar 2001 13:01:40 +0100


This kind of low level impl. where suspension points are known at runtime only,
cannot be implemented in jython
(at least not in a non costly and reasonable way).
Jython codebase is likely to just allow generators with suspension points known
at compilation time.

regards.

----- Original Message -----
From: Neil Schemenauer <nas@arctrix.com>
To: <python-dev@python.org>
Sent: Sunday, March 18, 2001 3:17 AM
Subject: [Python-Dev] Simple generators, round 2


> I've got a different implementation.  There are no new keywords
> and its simpler to wrap a high level interface around the low
> interface.
>
>     http://arctrix.com/nas/python/generator2.diff
>
> What the patch does:
>
>     Split the big for loop and switch statement out of eval_code2
>     into PyEval_EvalFrame.
>
>     Add a new "why" flag for ceval, WHY_SUSPEND.  It is similar to
>     WHY_RETURN except that the frame value stack and the block stack
>     are not touched.  The frame is also marked resumable before
>     returning (f_stackbottom != NULL).
>
>     Add two new methods to frame objects, suspend and resume.
>     suspend takes one argument which gets attached to the frame
>     (f_suspendvalue).  This tells ceval to suspend as soon as control
>     gets back to this frame.  resume, strangely enough, resumes a
>     suspended frame.  Execution continues at the point it was
>     suspended.  This is done by calling PyEval_EvalFrame on the frame
>     object.
>
>     Make frame_dealloc clean up the stack and decref f_suspendvalue
>     if it exists.
>
> There are probably still bugs and it slows down ceval too much
> but otherwise things are looking good.  Here are some examples
> (the're a little long and but illustrative).  Low level
> interface, similar to my last example:
>
>     # print 0 to 999
>     import sys
>
>     def g():
>         for n in range(1000):
>             f = sys._getframe()
>             f.suspend((n, f))
>         return None, None
>
>     n, frame = g()
>     while frame:
>         print n
>         n, frame = frame.resume()
>
> Let's build something easier to use:
>
>     # Generator.py
>     import sys
>
>     class Generator:
>         def __init__(self):
>             self.frame = sys._getframe(1)
>             self.frame.suspend(self)
>
>         def suspend(self, value):
>             self.frame.suspend(value)
>
>         def end(self):
>             raise IndexError
>
>         def __getitem__(self, i):
>             # fake indices suck, need iterators
>             return self.frame.resume()
>
> Now let's try Guido's pi example now:
>
>     # Prints out the frist 100 digits of pi
>     from Generator import Generator
>
>     def pi():
>         g = Generator()
>         k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L
>         while 1:
>             # Next approximation
>             p, q, k = k*k, 2L*k+1L, k+1L
>             a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
>             # Print common digits
>             d, d1 = a/b, a1/b1
>             while d == d1:
>                 g.suspend(int(d))
>                 a, a1 = 10L*(a%b), 10L*(a1%b1)
>                 d, d1 = a/b, a1/b1
>
>     def test():
>         pi_digits = pi()
>         for i in range(100):
>             print pi_digits[i],
>
>     if __name__ == "__main__":
>         test()
>
> Some tree traversals:
>
>     from types import TupleType
>     from Generator import Generator
>
>     # (A - B) + C * (E/F)
>     expr = ("+",
>              ("-", "A", "B"),
>              ("*", "C",
>                   ("/", "E", "F")))
>
>     def postorder(node):
>         g = Generator()
>         if isinstance(node, TupleType):
>             value, left, right = node
>             for child in postorder(left):
>                 g.suspend(child)
>             for child in postorder(right):
>                 g.suspend(child)
>             g.suspend(value)
>         else:
>             g.suspend(node)
>         g.end()
>
>     print "postorder:",
>     for node in postorder(expr):
>         print node,
>     print
>
> This prints:
>
>     postorder: A B - C E F / * +
>
> Cheers,
>
>   Neil
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev@python.org
> http://mail.python.org/mailman/listinfo/python-dev
>