What makes an iterator an iterator?

Terry Reedy tjreedy at udel.edu
Thu Apr 19 16:37:02 EDT 2007


"7stud" <bbxx789_05ss at yahoo.com> wrote in message 
news:1176961515.450458.189530 at p77g2000hsh.googlegroups.com...
| On Apr 18, 8:38 pm, "Terry Reedy" <tjre... at udel.edu> wrote:
| >
| > One very good way to get an iterator from an iterable is for .__iter__ 
to
| > be a generator function.
|
| Ahhh.  That eliminates having to deal with next().next constructs.

There never was any 'having' to deal with such a thing.  I suggest 
completely forgetting .next().next and variants.

| Nice.
|
| > snip all examples of bad code that violate the iterator rule
| > by improperly writing .next as a generator function
|
| What iterator rule states that .next can't be a generator function?

How about the programming rule that a function should return what you want 
it to return, or at least something 'close'?

I gave the iterator rule in brief at the top of my posting, but here is 
again with several more words: the next method of an iterator for an actual 
or virtual collection has no input other than self (and internally stored 
information).  Each time it is called, its output is either 'another' 
object in the collection, if there is at least one, or a StopIteration 
exception.  For sequences, 'another' most be the next item after the last 
one returned (if any).  Whether or not duplicates are allowed depends on 
the collection type.

Each call of a generator function returns a new generator object.  It never 
raises StopIteration.  So making .next a generator function defines the 
collection as an infinite virtual collection (sequence or multiset) of 
generators.  If that is what is intended (which it is not in the examples 
posted), fine.  Otherwise, it is a mistake.

| My book says an iterator is any object with a .next method that is
| callable without arguments (Python in a Nutshell(p.65) says the same
| thing).

A complete interface specification specifies information flows in both 
directions, as I did before and again here.

| I've read recommendations that an iterator should additionally contain
| an __iter__() method, but I'm not sure why that is.  In particular PEP
| 234 says:   [snip] should [snip]

In my view, the 'should' should be taken strongly, so that the iterator is 
also an iterable. It is certainly idiomatic to follow the advice. Then one 
can write code like

def f(iterable):
    iterator = iter(iterable)

instead of

def f(iterable):
    try: iterator = iter(iterable)
    except AttributeError: pass

Terry Jan Reedy






More information about the Python-list mailing list