Feedback on Until recipe

T

Thomas Nelson

Occasionally someone posts to this group complaining about the lack of
"repeat ... until" in python. I too have occasionally wished for such
a construct, and after some thinking, I came up with the class below.
I'm hoping to get some feedback here, and if people besides me think
they might use it someday, I can put it on the python cookbook. I'm
pretty happy with it, the only ugly thing is you have to use a
lambda. Ideally i'd like to just see
while Until(i<3)
but that doesn't work.
Please tell me what you think, and thanks for your time.

Tom

class Until:
""" ... print "hello"
... i += 1
hello
hello
hello ... print "hello"
hello
"""
yet = True
def __init__(self, mybool):
if self.__class__.yet or mybool():
self.__class__.yet = False
self.ans = True
else:
self.__class__.yet = True
self.ans = False

def __nonzero__(self):
return self.ans
 
S

Steve Holden

Thomas said:
Occasionally someone posts to this group complaining about the lack of
"repeat ... until" in python. I too have occasionally wished for such
a construct, and after some thinking, I came up with the class below.
I'm hoping to get some feedback here, and if people besides me think
they might use it someday, I can put it on the python cookbook. I'm
pretty happy with it, the only ugly thing is you have to use a
lambda. Ideally i'd like to just see
while Until(i<3)
but that doesn't work.
Please tell me what you think, and thanks for your time.

Tom

class Until:
"""
... print "hello"
... i += 1
hello
hello
hello
... print "hello"
hello
"""
yet = True
def __init__(self, mybool):
if self.__class__.yet or mybool():
self.__class__.yet = False
self.ans = True
else:
self.__class__.yet = True
self.ans = False

def __nonzero__(self):
return self.ans
First of all, I have to say it reads horribly. "while Until(...)" is
supposed to remind us of a *repeat* loop?

Secondly it isn't really what you want because the condition is still
being evaluated before the loop body is executed, when the idea of a
repeat loop is to terminate the loop after at least one iteration once
the condition is true. This is not strictly equivalent to your
conditions. Temporal logic is tricky.

By the way, isn't it always true that self.ans == not self.__class__.yet
(and why use a class variable, by the way, doesn't this stop you from
using nested loops)?

That's about all I can think of offhand. Sorry if it seems a bit
negative. I'm hoping it will spur you on to a better solution.

regards
Steve
regards
Steve
 
P

Paul McGuire

Occasionally someone posts to this group complaining about the lack of
"repeat ... until" in python. I too have occasionally wished for such
a construct, and after some thinking, I came up with the class below.
I'm hoping to get some feedback here, and if people besides me think
they might use it someday, I can put it on the python cookbook. I'm
pretty happy with it, the only ugly thing is you have to use a
lambda. Ideally i'd like to just see
while Until(i<3)
but that doesn't work.
Please tell me what you think, and thanks for your time.

Tom

class Until:
"""
... print "hello"
... i += 1
hello
hello
hello
... print "hello"
hello
"""
yet = True
def __init__(self, mybool):
if self.__class__.yet or mybool():
self.__class__.yet = False
self.ans = True
else:
self.__class__.yet = True
self.ans = False

def __nonzero__(self):
return self.ans

Class-level "yet" variable not a good idea. Loops can be nested:

i = 0
# this should loop once, since test is logically at the end of the
loop
while Until(lambda : i < 0 ):
print "hello"
i += 1
j = 0
while Until(lambda : j < 0 ):
print "byebye"
j += 1

This loops forever.

After tinkering with this a bit, I can see why you need a class
variable. In your outer loop, "Until(lambda : i < 0)" is evaluated
every time around the loop, creating a new Until object, so you can't
preserve looping state in the object, you have to do it in the class.

I used your idea to create an instance-level Until that survives
looping, but the requirements for construction are still onerous. In
essence, the instance-level util defers the break-on-condition by one
loop iteration.

class Until:
""" ... print "hello"
... i += 1
hello
hello
hello ... print "hello"
hello
"""
def __init__(self, mybool):
self.lastTest = True
self.mybool = mybool

def __nonzero__(self):
ret,self.lastTest = self.lastTest,self.mybool()
return ret

i = 0
uCond1 = Until(lambda : i < 0 )
uCond2 = Until(lambda : j < 0 )
while uCond1:
print "hello"
i += 1
j = 0
while uCond2:
print "byebye"
j += 1

-- Paul
 
P

Paul McGuire

I moved the state into the Until instance vs. the Until class, so that
it now supports nesting. But the calling syntax is even uglier - but
necessary to avoid creating a new Until instance each time around.
That is "while Until(blah):" evaluates and constructs a new Until
instance each time around the loop, so that is why the state had to be
kept in a class-level variable in your original design (which is why
nesting doesn't work).

class Until:
def __init__(self, mybool):
self.lastTest = True
self.mybool = mybool

def __nonzero__(self):
ret,self.lastTest = self.lastTest,self.mybool()
return ret

i = 0
u1 = Until(lambda : i < 0 )
while u1:
print "hello"
i += 1
j = 0
u2 = Until(lambda : j < 0 )
while u2:
print "byebye"
j += 1
 
C

Carsten Haese

I moved the state into the Until instance vs. the Until class, so that
it now supports nesting. But the calling syntax is even uglier - but
necessary to avoid creating a new Until instance each time around.
That is "while Until(blah):" evaluates and constructs a new Until
instance each time around the loop, so that is why the state had to be
kept in a class-level variable in your original design (which is why
nesting doesn't work).

class Until:
def __init__(self, mybool):
self.lastTest = True
self.mybool = mybool

def __nonzero__(self):
ret,self.lastTest = self.lastTest,self.mybool()
return ret

i = 0
u1 = Until(lambda : i < 0 )
while u1:
print "hello"
i += 1
j = 0
u2 = Until(lambda : j < 0 )
while u2:
print "byebye"
j += 1

Using iterators is a way around the problem of making a new instance
every time around the loop, but the calling syntax is not much nicer
since it is shoehorned into a for-loop. Note that I've renamed the beast
in order to reflect what it actually does: The loop body is repeated as
long as the given condition is true.

class RepeatAsLongAs(object):
def __init__(self, cond):
self.cond = cond
self.previousTest = True
def __iter__(self):
return self
def next(self):
ret, self.previousTest = self.previousTest, self.cond()
if not ret: raise StopIteration
return ret

i = 0
for _ in RepeatAsLongAs(lambda: i<0):
print "hello"
i += 1
j = 0
for _ in RepeatAsLongAs(lambda: j<0):
print "byebye"
j += 1

Having said that, I don't see myself ever using such a beast. The
equivalent code

while True:
# do something
if until_condition: break

is much more concise, much easier to understand, and it shows explicitly
that the condition is checked after the loop body is executed.

-Carsten
 
A

Antoon Pardon

Occasionally someone posts to this group complaining about the lack of
"repeat ... until" in python. I too have occasionally wished for such
a construct, and after some thinking, I came up with the class below.
I'm hoping to get some feedback here, and if people besides me think
they might use it someday, I can put it on the python cookbook. I'm
pretty happy with it, the only ugly thing is you have to use a
lambda. Ideally i'd like to just see
while Until(i<3)
but that doesn't work.
Please tell me what you think, and thanks for your time.

Maybe we should try to get the developers revive PEP 315.

This PEP whould introduce a do-while statement that looks
like the folowing:

do
statements
while condition
statements


this would be equivallent to:

while 1:
statements
if not condition:
break
statements


Those wanting something like:

repeat
statements
until condition


Could then write something like:

do
statements
while not condition
pass


Still not the most elegant but a vast improvement IMO.
 
M

MRAB

Maybe we should try to get the developers revive PEP 315.

This PEP whould introduce a do-while statement that looks
like the folowing:

do
statements
while condition
statements

this would be equivallent to:

while 1:
statements
if not condition:
break
statements

Those wanting something like:

repeat
statements
until condition

Could then write something like:

do
statements
while not condition
pass

Still not the most elegant but a vast improvement IMO.
At http://mail.python.org/pipermail/python-dev/2006-February/060718.html
Raymond Hettinger suggested removing the final colon after the 'while'
if there's no statement after it, which I agree with, although I would
prefer 'repeat' instead of 'do' (IMHO that doesn't suggest repetition
clearly enough):

repeat:
statements
while condition:
statements

and:

repeat:
statements
while condition
 
A

Antoon Pardon

At http://mail.python.org/pipermail/python-dev/2006-February/060718.html
Raymond Hettinger suggested removing the final colon after the 'while'
if there's no statement after it, which I agree with, although I would
prefer 'repeat' instead of 'do' (IMHO that doesn't suggest repetition
clearly enough):

repeat:
statements
while condition:
statements

and:

repeat:
statements
while condition

I wouldn't object to this. But more important than how it will look like
IMO is that it gets implemented. Acoording to your URL there is little
chance that this will be implemented before Py3k. A pity.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,265
Messages
2,571,069
Members
48,771
Latest member
ElysaD

Latest Threads

Top