[Python-3000] Using *a for packing in lists and other places

Talin talin at acm.org
Sun Mar 16 02:51:21 CET 2008



Guido van Rossum wrote:
> Also, yielding everything from an iterator:
> 
>>>> def flatten(iterables):
> ...     for it in iterables:
> ...         yield *it
> ...
>>>> L = [ a, (3, 4), {5}, {6: None}, (i for i in range(7, 10)) ]
>>>> flatten(L)
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> 
> What do people think?

(re-sending to the correct place - thanks Guido)

I've suggested something similar a while back:

http://mail.python.org/pipermail/python-list/2005-October/348485.html

At one point I was working on a algorithmic solver for mathematical 
equations using recursive generators to do backtracking search; being 
able to yield an entire generator's worth of output would have 
simplified it considerably.

Also, there's a potential optimization - if a generator is yielding the 
entire output of another generator, it might be possible to 'cut out the 
middleman' and have the ultimate consumer of the values read the 
innermost generator directly. I don't know how feasible that is, however.

All that being said: Using generators to implement backtracking search 
is much nicer than trying to do it with regular recursion and callbacks; 
But even nicer would be true coroutines.

Take for example the solver I mentioned, which basically is a unifier. 
What it does is take two trees (composed of nested tuples) and 
recursively walks them, matching as it goes. At each level, there may be 
several possible ways of doing a match; The algorithm iterates through 
each of these possibilities, invoking the lower-level matchers once for 
each possibility. The lower-level matcher may in turn find several 
possible matches, or may find none (meaning that the upper-level 
possibility didn't pan out.)

When the algorithm gets to a leaf, it yields a result. The caller of the 
algorithm receives essentially a stream of answers, which it can read as 
many or as few as it wishes.

Since generators can't operate across multiple stack frames, the way to 
construct this algorithm is to have each sub-matcher yield all of its 
answers to its parent. This is where the 'yield *' syntax comes in.

In the case of the equation solver, the 'answers' consist of possible 
variable bindings. So given the inputs 'x? + y?' and '1 + 2 + 3', the 
stream of answers is (applying the associative rule):

     (x = 1, y = 2 + 3)
     (x = 1 + 2, y = 3)
     ...and so on

Now, one final comment: PEP 342 promises that the new yield semantics 
can be used to implement true coroutines. But I don't see how to 
actually make that work. Has anyone actually done this?

-- Talin


More information about the Python-3000 mailing list