I need to emulate a do-while loop in a Python program. Unfortunately, the following straightforward code does not work:
list_of_ints = [ 1, 2, 3 ]
iterator = list_of_ints.__iter__()
element = None
while True:
if element:
print element
try:
element = iterator.next()
except StopIteration:
break
print "done"
Instead of "1,2,3,done", it prints the following output:
[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', ' File "test_python.py", line 8, in <module>
s = i.next()
', 'StopIteration
']
What can I do in order to catch the 'stop iteration' exception and break a while
loop properly?
An example of why such a thing may be needed is shown below as pseudocode.
State machine:
s = ""
while True :
if state is STATE_CODE :
if "//" in s :
tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
state = STATE_COMMENT
else :
tokens.add( TOKEN_CODE, s )
if state is STATE_COMMENT :
if "//" in s :
tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
else
state = STATE_CODE
# Re-evaluate same line
continue
try :
s = i.next()
except StopIteration :
break
I am not sure what you are trying to do. You can implement a do-while loop like this:
while True:
stuff()
if fail_condition:
break
Or:
stuff()
while not fail_condition:
stuff()
What are you doing trying to use a do while loop to print the stuff in the list? Why not just use:
for i in l:
print i
print "done"
Update:
So do you have a list of lines? And you want to keep iterating through it? How about:
for s in l:
while True:
stuff()
# use a "break" instead of s = i.next()
Does that seem like something close to what you would want? With your code example, it would be:
for s in some_list:
while True:
if state is STATE_CODE:
if "//" in s:
tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
state = STATE_COMMENT
else :
tokens.add( TOKEN_CODE, s )
if state is STATE_COMMENT:
if "//" in s:
tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
break # get next s
else:
state = STATE_CODE
# re-evaluate same line
# continues automatically
Here's a very simple way to emulate a do-while loop:
condition = True
while condition:
# loop body here
condition = test_loop_condition()
# end of loop
The key features of a do-while loop are that the loop body always executes at least once, and that the condition is evaluated at the bottom of the loop body. The control structure show here accomplishes both of these with no need for exceptions or break statements. It does introduce one extra Boolean variable.
My code below might be a useful implementation, highlighting the main difference between do-while vs while as I understand it.
So in this one case, you always go through the loop at least once.
first_pass = True
while first_pass or condition:
first_pass = False
do_stuff()
do {
stuff()
} while (condition())
->
while True:
stuff()
if not condition():
break
You can do a function:
def do_while(stuff, condition):
while condition(stuff()):
pass
But
1) It's ugly.
2) Condition should be a function with one parameter, supposed to be filled by stuff (it's the only reason not to use the classic while loop.)
Exception will break the loop, so you might as well handle it outside the loop.
try:
while True:
if s:
print s
s = i.next()
except StopIteration:
pass
I guess that the problem with your code is that behaviour of break inside except is not defined. Generally break goes only one level up, so e.g. break inside try goes directly to finally (if it exists) an out of the try, but not out of the loop.
Related PEP: http://www.python.org/dev/peps/pep-3136
Related question: Breaking out of nested loops
Here is a crazier solution of a different pattern -- using coroutines. The code is still very similar, but with one important difference; there are no exit conditions at all! The coroutine (chain of coroutines really) just stops when you stop feeding it with data.
def coroutine(func):
"""Coroutine decorator
Coroutines must be started, advanced to their first "yield" point,
and this decorator does this automatically.
"""
def startcr(*ar, **kw):
cr = func(*ar, **kw)
cr.next()
return cr
return startcr
#coroutine
def collector(storage):
"""Act as "sink" and collect all sent in #storage"""
while True:
storage.append((yield))
#coroutine
def state_machine(sink):
""" .send() new parts to be tokenized by the state machine,
tokens are passed on to #sink
"""
s = ""
state = STATE_CODE
while True:
if state is STATE_CODE :
if "//" in s :
sink.send((TOKEN_COMMENT, s.split( "//" )[1] ))
state = STATE_COMMENT
else :
sink.send(( TOKEN_CODE, s ))
if state is STATE_COMMENT :
if "//" in s :
sink.send(( TOKEN_COMMENT, s.split( "//" )[1] ))
else
state = STATE_CODE
# re-evaluate same line
continue
s = (yield)
tokens = []
sm = state_machine(collector(tokens))
for piece in i:
sm.send(piece)
The code above collects all tokens as tuples in tokens and I assume there is no difference between .append() and .add() in the original code.
The way I've done this is as follows...
condition = True
while condition:
do_stuff()
condition = (<something that evaluates to True or False>)
This seems to me to be the simplistic solution, I'm surprised I haven't seen it here already. This can obviously also be inverted to
while not condition:
etc.
I believe that this do-while simulation on python has a syntax format closest to the do-while structure format present in C and Java.
do = True
while do:
[...]
do = <condition>
Python 3.8 has the answer.
It's called assignment expressions. from the documentation:
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
for a do - while loop containing try statements
loop = True
while loop:
generic_stuff()
try:
questionable_stuff()
# to break from successful completion
# loop = False
except:
optional_stuff()
# to break from unsuccessful completion -
# the case referenced in the OP's question
loop = False
finally:
more_generic_stuff()
alternatively, when there's no need for the 'finally' clause
while True:
generic_stuff()
try:
questionable_stuff()
# to break from successful completion
# break
except:
optional_stuff()
# to break from unsuccessful completion -
# the case referenced in the OP's question
break
While loop:
while condition:
print("hello")
Do while loop:
while True:
print("hello")
if not condition:
break
Also you can use any true boolean value as condition:
while 1:
print("hello")
if not condition:
break
Another variant:
check = 1
while check:
print("hello")
check = condition
Quick hack:
def dowhile(func = None, condition = None):
if not func or not condition:
return
else:
func()
while condition():
func()
Use like so:
>>> x = 10
>>> def f():
... global x
... x = x - 1
>>> def c():
global x
return x > 0
>>> dowhile(f, c)
>>> print x
0
while condition is True:
stuff()
else:
stuff()
Why don't you just do
for s in l :
print s
print "done"
?
If you're in a scenario where you are looping while a resource is unavaliable or something similar that throws an exception, you could use something like
import time
while True:
try:
f = open('some/path', 'r')
except IOError:
print('File could not be read. Retrying in 5 seconds')
time.sleep(5)
else:
break
You wondered:
What can I do in order to catch the 'stop iteration' exception and break a while loop properly?
You could do it as shown below and which also makes use of the assignment expressions feature (aka “the walrus operator”) that was introduced in Python 3.8:
list_of_ints = [1, 2, 3]
iterator = iter(list_of_ints)
try:
while (element := next(iterator)):
print(element)
except StopIteration:
print("done")
Another possibility (that would work from Python 2.6 to 3.x) would be to provide a default argument to the built-in next() function to avoid the StopIteration exception:
SENTINEL = object() # Unique object.
list_of_ints = [1, 2, 3]
iterator = iter(list_of_ints)
while True:
element = next(iterator, SENTINEL)
if element is SENTINEL:
break
print(element)
print("done")
See if this helps :
Set a flag inside the exception handler and check it before working on the s.
flagBreak = false;
while True :
if flagBreak : break
if s :
print s
try :
s = i.next()
except StopIteration :
flagBreak = true
print "done"
For me a typical while loop will be something like this:
xBool = True
# A counter to force a condition (eg. yCount = some integer value)
while xBool:
# set up the condition (eg. if yCount > 0):
(Do something)
yCount = yCount - 1
else:
# (condition is not met, set xBool False)
xBool = False
I could include a for..loop within the while loop as well, if situation so warrants, for looping through another set of condition.
while True:
try:
# stuff
stuff_1()
if some_cond:
continue
if other_cond:
break
stuff_2()
finally:
# condition
if not condition:
break
[x] condition checked only after running stuff
[x] stuff is not a function call
[x] condition is not a function call
[x] stuff can contain flow control
[ ] Avoid checking condition if stuff called break (can be done with another boolean)
The built-in iter function does specifically that:
for x in iter(YOUR_FN, TERM_VAL):
...
E.g. (tested in Py2 and 3):
class Easy:
X = 0
#classmethod
def com(cls):
cls.X += 1
return cls.X
for x in iter(Easy.com, 10):
print(">>>", x)
If you want to give a condition to terminate instead of a value, you always can set an equality, and require that equality to be True.
Related
I am implementing the scenario in which i have multiple if,elif,else loops.My problem is when the condition met ,its coming out of the program and exits the program .
Expected Behavior - After successful completion it should not exit but rather again show me the options to select .Only after pressing something like cntrl+c it should exit out the program.
class Manager:
def __init__(self):
self.not_useful_tests = []
self.sdsf
def sdsf(self):
try:
input = raw_input()
if input == 'x':
self.not_useful_tests.append(0)
else:
if input == 1:
verify = self.ABC()
return verify
if input == 2:
verify = self.xyz()
return verify
if input == 3:
verify = self.hyg()
return verify
if input == 4:
verify = self.fgh()
return verify
if input == 5:
verify = self.qwe()
return verify
except KeyboardInterrupt as e:
print "Exception caught : " + str(e)
return None
How to achieve this beahvior ? What to add in the code so as to achieve the task ?
To repeat something while some condition is true, use a while loop:
while True:
input = raw_input()
if input == 1:
return 'some value'
if input == 2:
return 'some other value'
If you don't want to return a function result, but rather want to continue execution outside of the loop, i.e. 'break out of the loop' use break:
while True:
input = raw_input()
if input == 1
print('doing something')
break
if input == 2
print('doing something else')
break
print('Continuing here')
And if that's what you want, you can also set a condition to end the loop like this:
result = None
while result is None:
input = raw_input()
if input == 1:
result = 'x'
if input == 2:
result = 'y'
print('will continue here if result has a value')
I have some code that is basically a demo for how dict works. My problem is, I am not sure exactly when it is calling the process_order() function. It seems like the main loop (go_shopping) never calls it, but the script seems to work. The go_shopping function calls get_item, but that doesn't call process_order either. I am also having trouble with the line if not process_order(order, cart):. What does the if not part mean in this case? Is that where it is calling process_order? It doesn't seem like it from the print statements, other wise it should print 'if not' when you add an item to the cart dictionary object.
Am I on the right track or missing something simple?
Code:
#!/usr/bin/python3.5
def get_item():
print("[command] [item] (command is 'a' to add, 'd' to delete, 'q' to quit.)")
line = input()
command = line[:1]
item = line[2:]
return command, item
def add_to_cart(item, cart):
if not item in cart:
cart[item] = 0
cart[item] += 1
def delete_from_cart(item, cart):
if item in cart:
if cart[item] <= 0:
del cart[item]
else:
cart[item] -= 1
def process_order(order, cart):
command, item = order
if command == "a":
add_to_cart(item, cart)
print('added to cart')
elif command == "d" and item in cart:
delete_from_cart(item, cart)
elif command == "q":
return False
print ('end process_order func')
return True
def go_shopping():
cart = dict()
while True:
print ('start main loop')
order = get_item()
print ('exited process_order')
if not process_order(order, cart):
print ('if not')
break
print ('while loop end')
print (cart)
print ("Finished!")
go_shopping()
Thing is, I am not really sure of your problem. But you seem concerned with the moment when process_order method is called.
When you write
if not process_order(order, cart)
it must be seen as follows (just adding parentheses):
if (not process_order(order, cart))
So you're asking Python to do something if the condition not process_order(order, cart) is true. So, Python must know the boolean value of the expression not process_order(order, cart).
This expression is composed of a unary operator, not, and a non-elementary expression, process_order(order, cart). That latter expression needs to be evaluated, so Python has to run the process_order method.
Therefore, when you write if not process_order(order, cart), the process_order method is indeed executed.
The code that I provided below prints the output one line at a time. However, I want to rewrite the code to print all the content all together at once.
def filters():
for LogLine in Log:
flag = True
for key,ConfLine in Conf.items():
for patterns in ConfLine:
print patterns
if re.match((DateString + patterns), LogLine):
flag = False
break
if(flag == False):
break
if(flag):
print LogLine
Thanks
Here's the general technique:
lines = []
for ...
lines.append(<whatever you were going to print>)
print '\n'.join(lines)
There is one thing that I would do. I would initialize an empty dictionary or empty list and then append all the items to the empty dictionary or empty list. Finally print the output all together at once.
def filters():
mypatterns=[]
for LogLine in Log:
flag = True
for key,ConfLine in Conf.items():
for patterns in ConfLine:
print patterns
mypatterns.append(patterns)
if re.match((DateString + patterns), LogLine):
flag = False
break
if(flag == False):
break
if(flag):
print LogLine
print mypatterns
Is there any way to enter try statement once again after catching the exception in the first try?
Now I'm using "while" and "if" statements and it is making the code messy.
Any ideas?
Will try to simplify it as possible, sorry that have no logic...
run = True
tryAgain = True
a=0
while run:
try:
2/a
except Exception:
if tryAgain:
tryAgain = False
a = 1
else:
run = False
You could try using a break statement in your try block:
while True:
try:
# try code
break # quit the loop if successful
except:
# error handling
Considering you are doing this in a while, then you can make use of continue to just continue back to the beginning of the while loop:
tryAgain = True
a=0
while True:
try:
2/a
break # if it worked then just break out of the loop
except Exception:
if tryAgain:
continue
else:
# whatever extra logic you nee to do here
I like using a for loop so that the trying and trying doesn't go on forever. Then the loop's else clause is a place to put the "I give up" code. Here is a general form that will support 'n' retries > 1:
a=0
num_tries = 5
for try_ in range(0,num_tries):
try:
2/a
except Exception:
print("failed, but we can try %d more time(s)" % (num_tries - try_ - 1))
if try_ == num_tries-2:
a = 1
else:
print("YESS!!! Success...")
break
else:
# if we got here, then never reached 'break' statement
print("tried and tried, but never succeeded")
prints:
failed, but we can try 4 more time(s)
failed, but we can try 3 more time(s)
failed, but we can try 2 more time(s)
failed, but we can try 1 more time(s)
YESS!!! Success...
I'm new to Python, so this may not be best practice. I returned to the try statement after triggering the exception by lumping everything into a single function, then recalling that function in the except statement.
def attempts():
while True:
try:
some code
break #breaks the loop when sucessful
except ValueError:
attempts() #recalls this function, starting back at the try statement
break
attempts()
Hope this addresses your question.
I have the following code:
def funct():
print("beggining function")
a = int(input)
if a == 1:
return True
else:
return False
while funct():
#Rest of the code
Every time the while loop repeats it executes the function, so it prints "beggining function". I want to avoid this, what can I do?
A while <condition> loop works as follows:
it checks condition.
if condition evaluates to True, it executes the upcoming code one time. Then it goes back to 1.
if condition evaluates to False, it skips the upcoming code and goes through the rest of the code.
So what you are seeing here is the intended way for while to work.
To prevent this header from being printed every time, just move it out of the while:
def funct():
a = int(input)
if a == 1:
return True
return False # no need to check anymore
print("beggining function") # here
while funct():
#Rest of the code
Try to this
def funct():
print("beggining function")
a = int(input())
if a == 1:
return True
else:
return False
while funct() == 1:
funct()
you enter input 1 loop will continue...