# Enhanced Generators - reiterable x-functions

Oren Tirosh oren-py-l at hishome.net
Sun Feb 3 09:25:31 CET 2002

```On Sat, Feb 02, 2002 at 10:05:11PM -0500, Kragen Sitaker wrote:
> In any case, it isn't clear to me that it's more useful to be able to
> say:
>     mymap = xmap(f, xs)
>     for ii in zs:
> 	for jj in mymap:
> 	    do_something(ii, jj)
> than to have to say:
>     for ii in zs:
> 	for jj in xmap(f, xs):
> 	    do_something(ii, jj)

Bingo. Your example clearly shows how re-iterable x-functions will behave
as expected in cases where non-reiterable xmap will produce a surprising
result.  My definition of surprising in this case is "behaves differently
if you remove the x".

Here's an even better example:

>>>alphabet = xmap(chr, xrange(ord('a'), ord('z')+1))
>>>twoletterwords = [a+b for a in alphabet for b in alphabet]
>>>print list(twoletterwords)

This example will produce strange results with non-reiterable xmap.  If
you remove the x from xmap it suddenly starts to work.

The x-functions are already lazy in reading from their sources - why
should they be eager in asking their sources for an iterator?.  This
half-lazy half-eager chimera is the true source of this inconsistency.

> So the upside of restartable xmap() etc. is that it saves you a lambda
> and a lambda call when you need it; the downside is that it gives you
> a function whose semantics subtly break when it's applied to
> nonrestartable iterators.

There's nothing subtle about that.  The iter() function, by definition,
returns an object that changes each time you reference it.  It's about
as surprising as the fact that the expression 'itr.next()' returns a
different result each time you evaluate it.

The iter() function is useful in code blocks with the appropriate loop
structures and try/except clauses.

Inside expressions, iterators should be kept as invisible plumbing.  This
ensures that expressions of arbitrary complexity using x-functions can be
re-iterated as many times as you like.

Oren

```