Need help understanding this while loop

Thanks for the reply.

Why does 3 cause an infinite loop?

Three is less than or equal to five, so the loop condition is true, and the loop body is entered. Then, there is nothing inside the body of the loop that ever updates the value to anything other than three, so every time the loop body finishes and the loop condition is evaluated again, it will still always be true.

Edit: Just to be clear, in my example, this is the entire loop:

current_number = 3
while current_number <= 5:
    print(current_number)

print("done")

I’ve added a print("done") to hopefully make it clear that there is only one line inside the loop, and that line does not update current_number. The print("done") will never be reached.

Ah I see. Thanks.

Well this, I can’t possibly understand since I didn’t learn any of it yet lol.

You’re overthinking this.

print() does nothing to the value or the variable. It just displays
the current value. What gets displays depends on where the print() is:
before or after the increment.

Think of it like one of those stupid card based magic tricks: you, the
mark, pick a card and show it to the audience and not to the magician -
it’s a nice clean card. This is the first print(). The magician asks
you to scribble on the card so that you can rwecognise it later, and you
show it to the audience so that they see what you’ve scribbled. This is
the second print(). Now you insert the card at a random place in the
deck, the magician fails to find it and is laughed off the stage.

The code runs exactly the same way with or without the print()s; all
their presence does is show the value to the audience at that point in
the loop.

1 Like

Speaking of being on the right track, let’s give this a shot. Let’s reconsider the original diagram with a slight modification:

Here I have added two cars, one blue and one green. Each car is responsible for delivering their respective cargo around the loop. In the diagram, it shows the load that each car is responsible for. As before, create two columns, and write down the values during each iteration that is valid. By valid, I mean when the value of the variable current_number is in the diamond above and being compared satisfying the conditional statement less than or equal to 5.

Now imagine that you’re pushing each car slowly around the loop as highlighted by the arrows. The green car is being pushed by your left hand and the blue car is being pushed by your right hand. Now, as stated before, both cars ONLY re-enter the loop if the current_number is less than or equal to 5. If the condition is not satisfied, the loop is exited immediately.

Give that a shot. Maybe interactive participation will aid in the understanding.

Thanks for the analogy. A little confusing, but I think I understand what’s going on in the loops now.

After searching online I think I understand it now. Thanks for this post.

After about five days I think I finally understand this now. I still think it’s odd, but I think I get it. Hopefully I won’t run into it often. Thank you everybody for helping me. I appreciate this community’s effort.

Now that I think I understand this, I want to get back to this post. Is there ever a reason why I’d need to use a while loop instead of a for loop for this kind of iteration? Can a for loop do anything a while loop can do, and better?

I can finally move on to the next part of this chapter.

well, if you take my example above the async thread is just a dumb worker and does not know for how long (but happy :melting_face:)

Any for loop can be rewritten as a while loop that manages the iterator explicitly; I think it’s self-evident that for loops provide a more readable alternative to doing that. You can rewrite the for loop

for i in x:
    do_something()

using the following while loop:

x_iter = iter(x)
while True:
    try:
        i = next(x_iter)
    except StopIteration:
        break

    do_something()
del x_iter

It gets a little more complicated when you need to accommodate continue, break, and an else clause on the for loop.

On the other hand, rewriting any while loop as a for loop would require writing an appropriate iterator to capture what the while loop is doing. Sometimes that may be straightforward, but other times it might require far more work than the simple boilerplate code needed to turn a for into a while.

Just FYI, you can reply to many people in one post by simply selecting the relevant text you want to reply to on each post and clicking the Quote button that pops up. That avoids you having to make a half dozen posts, is much clearer what you’re replying to, and only pings people following the thread with one notification rather than several :slight_smile:

Good question; the answer depends on what you mean by “this kind of iteration”. In summary, if you have or can easily create an iterable/iterator (such as a collection, file, range, generator, itertools iterator, etc.), and you want to iterate exactly once through each item in the iterable/iterator in a fixed order (either the order of the iterable, or something it can easily be reordered to a priori), then you want a for loop. That covers a large majority of cases in most Python use cases, but certainly not all.

Otherwise, if either of those conditions can’t be easily met, then you likely want a while loop instead. For example, the most common case of the former is almost any infinite loop, e.g. an asyncio event loop, GUI event loop, handler for reading incoming network connections, etc; or, where you want to repeat some action until some condition is reached. In terms of the latter, this would include cases where you want to skip around in your data structure, iterate an arbitrary number of times on items, go back to previous items, or most other cases where iteration happens in a difficult to predictable, dynamic or otherwise not easily modeled a priori fashion—for example, a binary search.

Or, at least for a while True loop, you could just cop out and do the equivalent (except you get a iteration counter “for free” if you want it):

for __ in itertools.count():
    ...

And to handle while loops with conditions:

for __ in itertools.count():
    if not <condition>:
        break
    ...

The latter case’s behavior would differ in one (rather uncommon) respect: if there was a (rarely-used) else block after the loop, it would not fire if <condition> became false (since the loop was broken out of manually), whereas it would in the equivalent while loop. Of course, you could replicate that behavior too by e.g. setting some variable normal_exit to True immediately before the break and changing the else to an if normal_exit.

You can often rewrite

while condition:

to

for _ in iter(lambda: bool(condition), False):

(The bool() call might not be necessary.)

For a simple loop, I prefer for loop as it feels natural and easy to me. Consider your example in the 1st post, it is simpler in for loop as follows:

for i in range(5):
    print(i+1)

IMHO, while loop is just a repeated if condition. You need it only when you want to check multiple conditions.
For instance,

current_number = 1
while current_number <= 5 and current_number * current_number <= 20:
    print(current_number)
    current_number += 1

You will get 1, 2, 3, 4.

Or you want infinite loop forever

current_number = 1
while True:
    print(current_number)
    current_number += 1

Actually, as I and the others who already replied to this have described in detail, the use cases in which one should use a for loop vs. a while loop do not really have to do with the “simplicity” of the loop (after all, what could be “simpler” than while True?), nor the reasons with one particular developer’s personal opinions; but rather whether the use case involves a predetermined iteration over an iterable, and whether the desired task matches the purpose for which each construct exists.

The user’s question you quoted was itself a direct reply to a post making the same point, including a nearly identical example, so I’m not entirely sure what purpose repeating it here serves, sorry?

To note, ISTM that it makes more sense to specify the actual desired endpoints of the range from the start (as my example did)…

for i in range(1, 6):
    print(i)

…instead of iterating over a different range and only adjusting it later inside the print call.

Indeed; this is not merely just your own (humble or otherwise) personal opinion :slight_smile: , but rather the objective behavior of the logic, as described and demonstrated by our previous posts (minus the else block, and possible pathological cases).

I don’t understand what you’re trying to claim here about only needing it when checking “multiple conditions”, sorry. I’m not sure how the number of conditions one is checking has any relationship whatever with whether you’d want to use a while loop (as opposed to the considerations we’ve mentioned above)?

It is quite common to use while True when one needs an infinite loop, but as we’ve stated, ultimately the question of while vs for comes down to whether you’re iterating in a predetermined order over an iterable. In this case, given you are (the set of integers 1…infinity), it is considerably simpler and more idiomatic to use a for loop as we’ve illustrated above, i.e.:

for n in itertools.count(start=1):
    print(n)

I didn’t know I could do that. Thanks. :slight_smile:

I’ll come back to the rest of your reply when I understand this stuff more. Appreciate it and everyone else’s replies.

1 Like