Having tried this sort of thing out before, I'll note that both
'for' and 'in' will work on pseudo-sequence or sequence-like
objects that provide __len__(), and __getitem__( index ) methods.
> The catch is that you need to know how many values a particular
> iterator instance will yield, so you can't use it to simulate an
> infinite or indefinite sequence.
One kludge is just to make 'len()' *LIE*. Return a value that is
larger than any realistic value. This implies that your 'for'
will break on an appropriate value. ( And you need to raise
an exception to break out of an 'in' that is false! )
Also: 'for' appears to call len() method before each call to
getitem() method. So you only really have to lie a little bit -
only promise one more item. And if you're going to promise
one more, you might as well look ahead and cache the next item -
then you can *eventually* tell the truth.
However, these extra len() calls would seem to be an obvious
part of the 'for' to optomize out - so maybe we can't rely on
that method continuing to work.(?) Or is that len() a necessary
part of the expected semantics of 'for' over an object? ( This
also makes it clear why you should use the suggested 'for x in s[:]'
when the body is going to modify 's'. )
> If iterators become popular in Python, it might be possible to
> redefine the 'for' semantics and extend the interface to sequences to
> allow for loops over (pseudo-)sequences of indefinite length. But I
> don't know how much use there is for this, since it is generally just
> as easy to use a while loop for a loop over an indefinite sequence...
How about len() ==> None as a sign of an indefinite length sequence.
len() of a non-sequence raises an exception, so the meaning is not
overloaded. [ except that: ( None < 0 ), so the test is awkward. ]
I find iterators and sequences quite a natural way of dealing with a
number of problems. My *other* favorite language, Icon, has
co-expressions and co-routines ( the latter much like the basic2
example ) and an 'every' to force full evaluation. I think the object
system (IDOL) built on top of Icon uses coexpressions to make objects.
( Tim may be more knowledgable on this - I've never used Idol ) In
python, it's the other way around - objects are the primary means of
preserving state. I only wish it was a bit easier to create "quick"
co-expression like objects. The problem is that there's no easy way to
pass THUNKS or unevaluated expressions around in python except as
strings to eval/exec. But even if it's not as easy as I'ld like, it's
The other reason I tend to use 'for' over a sequence, has to do
with some issues of style I have raised before. Since Python has
no C-like assign and test, and I don't like to special case the
first assignment at the top of the loop, and even "while 'true' :
... if some_test() : break " , while I think it looks "cleaner",
tends to hide the logic of the loop - so if I can at all coerce
the logic into "for x in sequence: process(x)", I tend to do so.
So if I could think of a good proposal to make 'for' more
"object-oriented" ( i.e. behave differently for different
objects ), I'ld tend to be in favor of it. But I agree
that additional feature's aren't *necessary*, so I don't
think they are worth considering unless they can fit in
without much trouble.
How about something like:
for y in every f(x) :
meaning to continue to apply f(x) for a new value y.
The question is, what is the implied loop exit?
y == None
y in ( None, 0, '', , (,) ) # i.e. any 'false' value
no implied exit, must terminate by a raised signal in
f(x) or a explicit test/break in the body of the for.
[ Could there be a special "loop break" exception ,
which is caught and invisibly handled in loops ? ]
[Note: Icon handles this by having a special value for failure. ]
- Steve Majewski