[Python-ideas] "While" suggestion

Terry Reedy tjreedy at udel.edu
Thu Jul 3 21:31:32 CEST 2008

Facundo Batista wrote:
> 2008/7/3 George Sakkis <george.sakkis at gmail.com>:
>> There is already an idiom for this, although admittedly not obvious or
>> well-known:
>> for data in iter(lambda: my_file.read(1024), ''):
>>     do_something(data)
>> or in 2.5+:
>> from functools import partial
>> for data in iter(partial(my_file.read,1024), ''):
>>     do_something(data)
> Yes, but note that these feels like workarounds.

I disagree, and will explain.

To me, iterators are one of the great unifying concept of Python, and 
for statements are the canonical way to iterate.  The end of a sequence, 
if there is one, can be signaled by any sentinel object or exception. 
The iterator protocol abstracts away the different possible signals and 
replaces them all with one exception used just for this purpose and 
which therefore cannot conflict with any object in the sequence nor be 
confused with any unexpected exception raised by their production.  When 
used in a for statement, it separates the concern of detecting the end 
of the sequence from the concern of processing the items of the sequence.

So, in this view, making a block-reading-and-yielding iterator, if one 
does not exist out of the box, is the proper thing to do for processing 

While statements are for all other loops for which for statements do not 
work (including, sometimes, the code buried within a generator function).

The suggestion of 'while <expression> as <name>' proposes a new 
'expression-iterator' protocol for expression-produced sequences of 
non-null objects terminated by *any* null object.

-1 from me, because

a) It unnecessarily duplicates one of Python's gems.
b) The use of *all* null objects as sentinels is almost never what one 
wants in any particular situation.  If it is, it is easy enough to write

   def non_nulls(f):
     while True:
       o = f()
       if o: yield o
       else: raise StopIteraton # or just break

c) Using all nulls as sentinels restricts the sequence more than using 
just one.  It is also bug bait.  Suppose f returns next_number or None. 
  A slightly naive or careless programmer writes 'while f as x: ...'. 
At some point, f returns 0.  Whoops.

It is better to be specific and only terminate on the intended 
terminator.  For this example, iter(f,None), or iter(f,'' as George 
suggested for the OP's use case.  Careful programming is *not* a workaround.

Terry Jan Reedy

More information about the Python-ideas mailing list