[Python-Dev] PEP 340: Deterministic Finalisation (new PEP draft, either a competitor or update to PEP 340)

Ron Adam rrr at ronadam.com
Sun May 8 21:23:50 CEST 2005


Nick Coghlan wrote:


> Iterating over a sequence. If it's single-pass (and always single pass), you 
> should use a user defined statement instead.

> That's the technique suggested for the single-pass user defined statements. 
> However, a 'for loop with finalisation' is *still fundamentally an iterative 
> loop*, and the syntax should reflect that.

<in responce to do>
> The same keyword cannot be used for the looping vs non-looping construct, 
> because of the effect on the semantics of break and continue statements.

I disagree with this, I think 'do' would work very well for both single 
pass, and multiple pass, blocks.

In this example 'do' evaluates as True until the generator ends without 
returning a value:

def open_file(name,mode):
     f = open(name,mode)
     try:
         yield f
     finally:
         f.close()

Do f from open_file(name,mode):
    for line in f:
    	print line.rstrip()

On the first try, it gets f, so the do expression evaluates as True and 
the BLOCK is run.

On the second try, instead of getting a value, the finally suite is 
executed and the generator ends, causing the do expression to evaluate 
as False.

If a continue is used, it just skips the end of the 'do' body, and then 
weather or not to loop is determined by weather or not the 'do 
expression evaluates as True or not.

A break skips the rest of the 'do' body and execute the generators 
finally.

This works the same in both single pass and multi pass situations.

The difference is by using a truth test instead of iterating, it better 
represents what is happening and opens up a few options.

There's also the possibility to use conditional looping based on the 
value returned from the generator.

do VAR from EXPR if VAR==CONST:
    BLOCK

This is a bit verbose, but it reads well. :-)

But that is really just a short cut for:

do VAR from EXPR:
     if VAR != CONST:
         break
     BLOCK


The Syntax might be:

    do ([VAR from] EXPR1) | (VAR from EXPR1 if EXPR2): BODY


>>I don't have an opinion on user defined statements yet.  But I think 
>>they would be somewhat slower than a built in block that does the same 
>>thing.
>  
> What do you mean by 'built in block'? The user defined statements of the PEP 
> redraft are simply a non-looping version of PEP 340's anonymous block statements.

Ok, my mistake, I thought you were suggesting the more general user 
defined statements suggested elsewhere.


> No, the else clause on loops is a little known part of present day Python - it 
> executes whenever the loop terminates naturally (i.e. not via a break statement).

Hmm... ok, and the opposite of what I expected.  No wonder its a little 
known part.


> My PEP redraft, on the other hand, suggests the introduction of a 'for loop with 
> finalisation' that works fairly similarly to PEP 340's anonymous block statements.

Here is my current thinking.  It will be better to have 3 separate loops 
with three identifiable names, and have each work in distinctly 
different ways.  That simplifies, teaching, using, and reading the 
resulting code. IMHO.

    1.  For-loops: Fast efficient list iteration. No changes.

    2.  While-loops: Fast efficient truth test based loop. No changes.

    3.  Do-loops: An generator based loop with finalization:  This could 
be both single and multiple pass.  The difference is determined by 
weather or not the generator used loops the yield statement or not.


I think a good test is the retry example in the PEP.  A solution that 
can represent that clearly and concisely would be a good choice.

Maybe this could be made to work:

def auto_retry(n, exc):
     while n>0:
         try:
             yield True
             n = 0
         except exc:
             n -= 1

do auto_retry(3, IOError):
     f = urllib.urlopen("http://python.org/")
     print f.read()

The ability to propagate the exception back to the generator is what's 
important here.

The while version of this nearly works, but is missing the exception 
propagation back to the generator, the ability to pass back through the 
yield, and finalization if the outside while loop is broken before the 
generator finishes.

def auto_retry(n, exc):
     while n>1:
         try:
             yield True
             break
         except exc:
             n -= 1
     # finalize here
     yield None

import urllib
ar = auto_retry(3, IOError)
while ar.next():
     f = urllib.urlopen("http://python.org/")
     print f.read()

Although changing 'while' shouldn't be done. I think using 'do' for 
generator based loops would be good.

This isn't that different from PEP340 I think.  Maybe it's just comming 
to the same conclusion from a differnt perspective. <shrug> :-)

Cheers, Ron






More information about the Python-Dev mailing list