Ron Adam wrote:
> I agree, re-using or extending 'for' doesn't seem like a good idea to me.

I agree that re-using a straight 'for' loop is out, due to performance and 
compatibility issues with applying finalisation semantics to all such iterative 
loops (there's a reason the PEP redraft doesn't suggest this).

However, it makes sense to me that a "for loop with finalisation" should 
actually *be* a 'for' loop - just with some extra syntax to indicate that the 
iterator is finalised at the end of the loop.

An option other than the one in my PEP draft would be to put 'del' at the end 
of 
the line instead of before EXPR:

   for [VAR in] EXPR [del]:
       BLOCK1
   else:
       BLOCK2

However, as you say, 'del' isn't great for the purpose, but I was trying to 
avoid introduding yet another keyword. An obvious alternative is to use 
'finally' instead:

   for [finally] [VAR in] EXPR:
       BLOCK1
   else:
       BLOCK2

It still doesn't read all that well, but at least the word more accurately 
reflects the semantics involved.

If a new keyword is used to request iterator finalisation, it should probably 
include the word 'for' since it *is* a for loop:

   foreach [VAR in] EXPR:
       BLOCK1
   else:
       BLOCK2

That is, a basic 'for' loop wouldn't finalise the iterator, but a 'foreach' 
loop 
would. The other difference is that the iterator in the 'foreach' loop has the 
chance to suppress exceptions other than TerminateBlock/StopIteration (by 
refusing to be finalised in response to the exception).

The last option is to leave finalisation out of the 'for' loop syntax, and 
introduce a user defined statement to handle the finalisation:

   def consuming(iterable):
       itr = iter(iterable)
       try:
           yield itr
       finally:
           itr_exit = getattr(itr, "__exit__", None)
           if itr_exit is not None:
               try:
                   itr_exit(TerminateBlock)
               except TerminateBlock:
                   pass

   stmt consuming(iterable) as itr:
       for item in itr:
           process(item)

With this approach, iterators can't swallow exceptions. This means that 
something like auto_retry() would once again have to be written as a class:

   class auto_retry(3, IOError):
       def __init__(self, times, exc=Exception):
           self.times = xrange(times-1)
           self.exc = exc
           self.succeeded = False

       def __iter__(self):
           attempt = self.attempt
           for i in self.times:
               yield attempt()
               if self.succeeded:
                   break
           else:
               yield self.last_attempt()

       def attempt(self):
           try:
               yield
               self.succeeded = True
           except self.exc:
               pass

       def last_attempt(self):
           yield


   for attempt in auto_retry(3, IOError):
        stmt attempt:
            # Do something!
            # Including break to give up early
            # Or continue to try again without raising IOError

> I wonder how much effect adding, 'for-next' and the 'StopIteration' 
> exception check as proposed in PEP340, will have on 'for''s performance.

I'm not sure what you mean here - 'for' loops already use a StopIteration 
raised 
by the iterator to indicate that the loop is complete. The code you posted 
can't 
work, since it also intercepts a StopIteration raised in the body of the loop.

> I think a completely separate looping or non-looping construct would be 
> better for the finalization issue, and maybe can work with class's with 
> __exit__ as well as generators.

The PEP redraft already proposes a non-looping version as a new statement. 
However, since generators are likely to start using the new non-looping 
statement, it's important to be able to ensure timely finalisation of normal 
iterators as well. Tim and Greg's discussion the other day convinced me of this 
- that's why the idea of using 'del' to mark a finalised loop made its way into 
the draft. It can be done using a user defined statement (as shown above), but 
it would be nicer to have something built into the 'for' loop syntax to handle 
it.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.blogspot.com
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to