HiveBrain v1.2.0
Get Started
← Back to all entries
debugpythonMinor

Do-While loop in Python, with limit on the amount of 'do's

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thewhilewithlimitamountlooppython

Problem

I'm in a location with poor Internet access. In order to ensure that a call to an external service succeeds, I am wrapping the call in a pseudo-do-while in Python. Additionally, I am limiting the call to running a maximum of three times:

def post_safe(url, params):

    done = 0
    max_tries = 3
    messages = []

    while done<max_tries:
        try:
            response = requests.post(url, data=params)
        except Exception as e:
            messages.append(e)
            time.sleep(1)
        else:
            done = max_tries+1
        done += 1

    if done==max_tries:
        output = "%s\n" % (datetime.now().strftime('%Y-%m-%d %H:%M'),)
        output+= "requests() failed 3 times:\n"
        for m in messages:
            output+= m+"\n"
        print(output)

        return False

    return True


I personally am not satisfied with the 'Pythoness' of this code. It looks inelegant, and I would have preferred to use the type bool for done but that would require a second variable to count the iterations.

Is there a cleaner way to achieve a do-while in Python while limiting the amount of iterations?

Solution

Python has a language feature just for that: else clauses on loops.


Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement.

def post_safe(url, params):
    max_tries = 3
    messages = []

    for _ in range(max_tries):
        try:
            response = requests.post(url, data=params)
            return True
        except Exception as e:
            messages.append(e)
            time.sleep(1)

    else:
        print(datetime.now().strftime('%Y-%m-%d %H:%M'))
        print("requests() failed %d times:" % (max_tries))
        for m in messages:
            print(m)
        return False


I'd also make the following changes:

  • The else clause on the try block is unnecessary; it can be replaced with a break within the try block just after calling .post(). But in the end, you'll just end up returning True, so why not get out of there right away with return True? (For that matter, the else block that I just suggested is also unnecessary, as the else could be removed and its contents outdented by one level.)



  • It seems easier to print each line separately than to build a multi-line string to print all at once. You might want to consider logging instead.

Code Snippets

def post_safe(url, params):
    max_tries = 3
    messages = []

    for _ in range(max_tries):
        try:
            response = requests.post(url, data=params)
            return True
        except Exception as e:
            messages.append(e)
            time.sleep(1)

    else:
        print(datetime.now().strftime('%Y-%m-%d %H:%M'))
        print("requests() failed %d times:" % (max_tries))
        for m in messages:
            print(m)
        return False

Context

StackExchange Code Review Q#38766, answer score: 9

Revisions (0)

No revisions yet.