[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