3

I have a relatively large main() function where I need to check a variable several times at different places in the function and then decide if I should continue the loop accordingly, like so:

def main():
    while True:
        ...
        if foo.check():
            reset()
            continue
        ...

Where foo is working as a time keeper of sorts, therefore I need to check it at certain intervals. These 3 lines appear about 3 to 5 times within the function.

I hate how dirty this is, so is there a cleaner way to do this?

5
  • Are you 100 % sure your logic requires this arrangement into a loop with several interdependent continues? That smell a bit. Commented Nov 23, 2020 at 12:58
  • @dedObed Well, I need to do several tasks in each iteration, but if something takes to long, I'm going back to the beginning of the loop. However, if that time threshold is passed, I don't want to stop the current task; I want to finish it first. The only way I can think of is to check the time after each task has been completed. I should add that encapsulating each of these tasks into separate functions isn't possible without the use of a bunch of global variables, which is way worse in my humble opinion. Commented Nov 23, 2020 at 13:07
  • Aha, so the tasks have dependencies... could you elaborate on how? Maybe it is a nice linear pipeline? Commented Nov 23, 2020 at 18:48
  • @dedObed It is very linear, thankfully. Commented Nov 23, 2020 at 19:31
  • then maybe my answer would do? Or is there some another catch? Commented Nov 23, 2020 at 20:45

3 Answers 3

2

You haven't specified enough information. I have two questions:

  1. Is the call foo.check() idempotent meaning it always returns the same value and has no side-effects?
  2. Is there a path through the code where you can reach the nth call to foo.check() in the same block governed by the continue statement without first calling the n-1th occurrence?

If, for example, the answer to the answer is yes and the second question were no, then you could remove all but the first occurrence of the call to foo.check() because the return value is clearly False or else you would never reach the second occurence.

If the answer to the first question is yes and the second is yes, then if the call to foo_check() is expensive, I might consider up front setting:

check_result = foo.check()

and then replacing every call to foo_check() with check_result. But ultimately you still need to do all the checks. But in all cases you can create a function check_and_reset:

def check_and_reset():
    if foo_check():
        reset()
        return True
    return False

Then your code becomes:

if check_and_reset(): continue
Sign up to request clarification or add additional context in comments.

2 Comments

foo.check() always returns a boolean. Also, foo.check() changes over time, independent of what's going on in the rest of the block, so replacing each foo.check() with a single variable in the beginning of the loop is not viable.
Then I would suggest you create a function check_and_reset as I described above. That is really the best you can do.
0

I have two suggestions:

Suggestion 1: Create another function and call wherever you want.

Suggestion 2: Make it as a one-liner

if foo.check():reset();continue

1 Comment

I don't really understand what you mean by "Create another function and call wherever you want". How does that help?
0

If it is just a complex way to control some timing while running a set of tasks, I'd suggest to introduce a loop over the tasks. You can even easily pass partial results around:

def task_a():
    ...

def task_c(some_input):
    ...

tasks = [lambda x: task_a(), task_c]
last_stage_output = None

while True:
    reset()
    for task in tasks:
        if not foo.check():
            break 
        last_stage_output = task(last_stage_output)

This way, you make it clear that it is just a series of tasks to be done, it's simple to add, remove of reshuffle them, and the timing logic is concentrated in a single point.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.