Making the case for repeat

Raymond Hettinger python at rcn.com
Mon Jun 8 01:46:23 CEST 2009


[pataphor]
> So here is my proposed suggestion for a once and for all reconciliation
> of various functions in itertools that can not stand on their own and
> keep a straight face.

Interesting phraseology ;-)  Enticing and yet fallacious in its
presumption of known and accepted usability problems.  FWIW, when I
designed the module, I started by researching constructs that had
proven success in functional languages and then adapted them to the
needs of Python applications.  That being said, I'm always open to
hearing new ideas.

After reading this thread a couple times, I have a few thoughts
to offer.

1. The Pythonic Way(tm) is to avoid combining too much functionality
in a single function, preferring to split when possible.  That is why
ifilter() and ifilterfalse() are separate functions.

(FWIW, the principle is considered pythonic because it was articulated
by Guido and has been widely applied throughout the language.)

There is a natural inclination to do the opposite.  We factor code
to eliminate redundancy, but that is not always a good idea with
an API.  The goal for code factoring is to minimize redundancy.
The goal for API design is having simple parts that are easily
learned and can be readily combined (i.e. the notion of an
iterator algebra).

It is not progress to mush the parts together in a single function
requiring multiple parameters.

2. I question the utility of some combining repeat() and cycle()
because I've not previously seen the two used together.

OTOH, there may be some utility to producing a fixed number of cycles
(see the ncycles() recipe in the docs).  Though, if I thought this
need
arose very often (it has never been requested), the straight-forward
solution would be to add a "times" argument to cycle(), patterned
after repeat()'s use of a "times" argument.

3. Looking at the sample code provided in your post, I would suggest
rewriting it as a factory function using the existing tools as
components.  That way, the result of the function will still run
at C speed and not be slowed by corner cases or unused parameters.
(see the ncycles recipe for an example of how to do this).

4. The suggested combined function seems to emphasize truncated
streams (i.e. a fixed number of repetitions or cycles).  This is
at odds with the notion of a toolset designed to allow lazy
infinite iterators to be fed to consumer functions that truncate
on the shortest iterable.  For example, the toolset supports:

   izip(mydata, count(), repeat(datetime.now()))

in preference to:

   izip(mydata, islice(count(), len(mydata)), repeat(datetime.now
(),times=len(mydata)))

To gain a better appreciation for this style (and for the current
design of itertools), look at the classic Hughes' paper "Why
Functional
Programming Matters".

    http://www.math.chalmers.se/~rjmh/Papers/whyfp.pdf


Raymond




More information about the Python-list mailing list