Reputation: 241
I'm writing a simple parser that reads a file. I'm reading the file contents into a list. I iterate through the list and send each line as an instruction to an instrument.
I'm iterating through the list like this:
for i, line in enumerate(mylines):
I check for keywords in the file and do some simple things like:
Delay N: Sleeps for N in increments one second
Pause: Display a "Click to Continue" window
These work and of course were simple.
I'd like add a "Loop N .... EndLoop" where it will see the "Loop N" line, set a counter to N and make note of the index position of the next line (loop_start= i+ 1) of the for beginning of the loop.
Then keep iterating until it comes to the EndLoop, where I want to set i back to the noted beginning of the loop and decrement the counter.
How do can I reset the for loop index to get it to jump back to the beginning of the loop? Doesn't seem to be as simple as:
i = loop_start
or is it?
Here's my code:
def interate(self, mylines):
count = 0
level = logging.INFO
for i, line in enumerate(mylines):
time.sleep(0.01)
print(line)
print(i)
line = self.stripComments(line)
print(line)
count += 1
loop_started = 0
loop_count = 0
if not line or re.search("^\s*$", line):
#print('String is either empty or Blank or contain only spaces')
pass
else:
first_word = line.split()[0]
if(first_word == "Delay"):
second_word = line.split()[1]
if second_word.isnumeric() and int(second_word) > 0:
logger.log(logging.WARNING, "DelayingI " + second_word)
for i in range(int(second_word), 0, -1):
time.sleep(int(1))
logger.log(logging.WARNING, "... " + str(i))
elif self.is_float(second_word) and float(second_word)> 0:
intgr, dec = divmod( float(second_word), 1)
print("intgr: " + str(intgr))
logger.log(logging.WARNING, "DelayingF " + second_word)
for i in range(int(intgr), 0, -1):
time.sleep(int(1))
logger.log(logging.WARNING, "... " + str(i))
logger.log(logging.WARNING, "and " + str(dec) + "mS")
time.sleep(dec)
else:
logger.log(logging.ERROR, "Bad Number" + second_word)
print("Bad number")
elif(first_word == "Pause"):
top= tk.Toplevel(self.frame)
x = self.frame.winfo_x()
y = self.frame.winfo_y()
top.geometry("+%d+%d" % (x + 100, y + 200))
top.geometry("100x100")
top.configure(bg='#6699cc')
top.title("Child Window")
pause_var = tk.IntVar()
pause_button = tk.Button(top, text='Click to Continue', command=lambda: pause_var.set(1))
pause_button.place(relx=.5, rely=.5, anchor="c")
pause_button.wait_variable(pause_var)
top.destroy()
elif(first_word == "Loop"):
if loop_started == 0:
print("loop started at " + (str(i)))
loop_started = 1
second_word = line.split()[1]
if second_word.isnumeric() and int(second_word) > 0:
begin_loop = i+i
num_loops = second_word;
print("number of loops: " + str(num_loops))
elif(first_word == "EndLoop"):
print("loop end at" + (str(i)))
loop_count = loop_count+1
print("loop cout:" + (str(i)))
if loop_count != num_loops:
i=begin_loop
else:
loop_started = 0
loop_count = 0
else:
serialPort.write(bytes(line + '\n', encoding='utf-8'))
Thanks!
Upvotes: 0
Views: 383
Reputation: 184191
enumerate
is managing the index here and it always goes to the next one. it doesn't "add 1 to i
" such that decreasing i
will move it backward, it produces the next index (from an internal counter) and the for
loop assigns that to i
before beginning the iteration.
If you want to be able to change the index during iteration, the traditional way is to manage the index yourself and use a while
loop instead of for
. However, an alternative is to write your own enumerator that allows the index to be adjusted. For example:
class ListEnumerator:
def __init__(self, seq, start=0):
self.seq = seq
self.index = start - 1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index < len(self.seq):
return self.index, self.seq[self.index]
else:
raise StopIteration
# go back the given number of elements
def back(self, off):
self.index -= (off + 1)
# skip ahead the given number of elements
def skip(self, off):
self.index += off
# process the same item again on next iteration
def again(self):
self.index -= 1
# process the previous item on next iteration
def prev(self):
self.index -= 2
# process the given item on next iteration
def set(self, index):
self.index = index - 1
Usage:
items = [3, 1, 4, 1, 5, 2, 7, 2, 9]
for i, x in (e := ListEnumerator(items)):
print(i, x)
if x == 1:
items[i] = 0
e.prev()
Upvotes: 1