[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
blocks.
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