psychopy.org | Reference | Downloads | Github

Unable to force-end a loop using .finished and continueRoutine

Howdy!
I’m trying to code a program that restarts a loop (“Test”, nested inside “Parent_Test”) under a certain condition (“Njt”). Parent_Test randomly grabs data from a file every time it loops, and Test randomly selects a variable from that file. So ending the Test loop will restart Parent_Test and get a new file. To test this, I added a routine that restarts the parent loop if Njt == 1.

def restart_loop():
    Test_Parent.nReps+= 1
    Test.finished= True
    continueRoutine= False

if Njt == 1:
    restart_loop()

(all added in “Begin Routine”.)

According to the other posts I read, setting .finished= True to a loop will end it once the current routine (using continueRoutine= False) has ended. Despite this, it seems to finish the rest of the experiment normally each time. I checked to make sure the variables are being set correctly, and sure enough my console logs showed continueRoutine == True and Test.finished = True.

Since Test.finished wasn’t ending the loop, I added a variable (“skip_current_loop”) and tried manually skipping each of the routines left in the loop:

if skip_current_loop==True:
    continueRoutine= False

(added in “Each Frame” for every following routine)

I also updated the original code to include this:

skip_current_loop= False

def restart_loop():
    assignMappingType.nReps+= 1
    skip_current_loop= True
    assignMappingList.finished= True
    continueRoutine= False

if Njt == 1:
    restart_loop()

(replaces original code)
(Njt and skip_current_loop are both initialized before the experiment.)

This also is being ignored by the program, and the loop is never skipped.

For reference, here’s how the program is structured:

The Njt code goes in choiceFilter, and the skip_current_loop goes into every other routine shown. Some of the routines use timed elements (has Start/Stop times). I’m running v2021.2.3 on Windows 10, in Builder, all locally run. I verified with print's that choiceFilter is only seen as many times as the rest of the program plays out.

I’ve fussed with this for a few days now and have no idea what I’m doing wrong. All I want to do is end the loop on a condition. Am I missing something obvious? Is this a known bug? Any insight would be fantastic; thank you!

I haven’t studied this post in detail yet but two things occur to me.

  1. You can’t change the nReps of a loop once it has started. Set the nReps to a large number and then end the loop with code when you’ve finished with it.

  2. loopName.finished breaks the loop at the end of the current iteration, not the end of the current routine. To skip routines put continueRoutine =False in Begin Routine.

2 Likes

Thank you for the fast response!

I hadn’t realized that .finished only took hold at the end of the iteration; thank you for clarifying. Turns out continueRoutine = False works too, but for some reason the skip_current_loop var was only recognizing the initial False status and not updating from restart_loop(), so my skip code was never being hit. When I tried printing skip_current_loop within restart_loop(), it threw the following error:

UnboundLocalError: local variable 'skip_current_loop' referenced before assignment

Somehow the interpreter sees skip_current_loop as a local variable within the function even though it was defined globally before the routine and again globally inside the routine. It might be a bug, and messing with my code it only sporadically pops up, but I managed to work around it by referring to my .nReps counter and changing skip_current_loop globally with if’s, i.e.;

if assignMappingType.nReps == skip_current_loop:
    skip_current_loop= 0
else:
    skip_current_loop= 1

Hopefully some future passerby might find that helps. Thanks again for the response!

1 Like