Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Iteration, while loop, and for loop

105 views
Skip to first unread message

Elizabeth Weiss

unread,
Jun 28, 2016, 8:36:39 AM6/28/16
to
I understand this code:

words=["hello", "world", "spam", "eggs"]
for words in words
print(word + "!")

What I do not understand is:

words=["hello", "world", "spam", "eggs"]
counter=0
max_index=len(words)-1

while counter<=max_index:
word=words[counter]
print(word + "!")
counter=counter + 1



Both of these result in the same answer.
I do not understand the second code. What is counter?
Why do we use this code if we can use the simpler for loop?

If you could please explain the second code step by step that would be great!

Thank you!!!

Michael Selik

unread,
Jun 28, 2016, 9:16:11 AM6/28/16
to
On Tue, Jun 28, 2016 at 8:41 AM Elizabeth Weiss <cak...@gmail.com> wrote:

> I do not understand the second code. What is counter?
>

It looks like someone wanted to make a loop induction variable.
https://en.wikipedia.org/wiki/Induction_variable


> Why do we use this code if we can use the simpler for loop?
>

You should not. Use the first version, it's much better. Python for-loops
are preferable to while-loops.

BartC

unread,
Jun 28, 2016, 9:24:51 AM6/28/16
to
Imagine the words are printed in a book, one per page, and the pages are
numbered 0, 1, 2 and 3 (starting from 0 as is the perverse say of many
programming languages).

len(words)-1 is the number of pages in the book (4) less one to account
for the odd numbering. Max_index is then the number of the last page (3).

Counter then goes through the pages one by one, starting at page 0 and
ending at page 3 (ie. max_index), reading the word on each and printing
it out with "!" appended.

However, because the language is zero-based, this would have been better
written as:

num_words = len(words)

while counter < num_words: # or just while counter < len(words)

That's if you had to write it as while loop. With the for=loop version,
these details are taken care of behind the scenes.

--
Bartc

Joseph Lee

unread,
Jun 28, 2016, 9:26:51 AM6/28/16
to
Hi,
Answers inline.

-----Original Message-----
From: Python-list
[mailto:python-list-bounces+joseph.lee22590=gmai...@python.org] On Behalf
Of Michael Selik
Sent: Tuesday, June 28, 2016 6:16 AM
To: Elizabeth Weiss <cak...@gmail.com>; pytho...@python.org
Subject: Re: Iteration, while loop, and for loop

On Tue, Jun 28, 2016 at 8:41 AM Elizabeth Weiss <cak...@gmail.com> wrote:

> I do not understand the second code. What is counter?
>

It looks like someone wanted to make a loop induction variable.
https://en.wikipedia.org/wiki/Induction_variable

JL: Or access the array item via indexing.

> Why do we use this code if we can use the simpler for loop?
>

You should not. Use the first version, it's much better. Python for-loops
are preferable to while-loops.

JL: Indexing is useful if one wishes to assign something different to the
position represented by container[index]. But if you want a more elegant way
to access the actual object in question, then using the first fragment is
better (and more readable). For the most part, for loops are better, but
there are times when while loops are preferable such as when you don't know
the size of the input beforehand.

Cheers,
Joseph

-
https://mail.python.org/mailman/listinfo/python-list

BartC

unread,
Jun 28, 2016, 9:30:04 AM6/28/16
to
On 28/06/2016 14:15, Michael Selik wrote:
> On Tue, Jun 28, 2016 at 8:41 AM Elizabeth Weiss <cak...@gmail.com> wrote:
>
>> I do not understand the second code. What is counter?
>>
>
> It looks like someone wanted to make a loop induction variable.
> https://en.wikipedia.org/wiki/Induction_variable

I don't know if that helps; I've never heard of an induction variable.
And according to the first example in that link, then 'word' in the OP's
second example might be classed as an induction variable too! Confusing.

--
Bartc

Jussi Piitulainen

unread,
Jun 28, 2016, 9:42:51 AM6/28/16
to
Elizabeth Weiss writes:

[- -]

> What I do not understand is:
>
> words=["hello", "world", "spam", "eggs"]
> counter=0
> max_index=len(words)-1
>
> while counter<=max_index:
> word=words[counter]
> print(word + "!")
> counter=counter + 1

# make it so that counter == 0
counter=0

# make it so that max_index is the greatest valid index to words (unless
# words is empty -- it would be simpler and idiomatic to make end_index
# be the first invalid index aka len(words), but make your life that
# little bit harder because ... reasons?)
max_index=len(words)-1

while counter<=max_index:

# Since we reached this point, counter is at most max_index, and is
# a valid index unless words is empty. If the test was instead
# counter < end_index, it would definitely be valid, or we wouldn't
# be *here*. Anyway, the first time at this point, counter == 0, the
# second time counter == 1, ...

# Set word to the item of words indicated by counter. First time at
# this point, words[0], second time, words[1], ...; print it.
word=words[counter]
print(word + "!")

# Make it so that counter is one larger than it used to be. In
# particular, it is closer to being larger than max_index so that we
# are eventually done with this loop.
counter=counter + 1

# At this point, the loop condition is tested again with the new
# value of counter(*) and when that new value is such it is no
# longer the case that counter<=max_index, looping ends.

# When we reach this point, the loop condition is false (or there has
# been another kind of exit from the loop): counter == max_index + 1.

(*) Now the thread may go into yet another tangent on how that "new
value" is really not a value but is the value of an immutable object
that is the value of a reference pointer in a box that is tied to a
puppy that is dancing on the point of a pin. You may or may not find
that helpful. Also, one or more of these things may be a name or have a
name.

> Both of these result in the same answer.
> I do not understand the second code. What is counter?
> Why do we use this code if we can use the simpler for loop?

Some loops are not easily written as for loops. This is not one of them.

For loops are easy to rewrite as while loops, so while loops may be
considered theoretically more fundamental. Other theoretical models
would express while loops with even more fundamental mechanisms (or they
can be quite practical models, though not directly available in Python
for this purpose or at all: conditional jumps to a labelled region of
program code, or function calls).

You need to get used to how program elements like counter behave. There
are events in the execution of a program that make it so that such
program elements stand for particular things (like numbers) in a
dependable way, in certain specific regions of code, until some new
event. The statement involving a single equals sign is one such event;
each entry to a for loop is another; a function call is yet another.

(I see that I have used the word "thing" about things that I really do
think of as things in the context of a Python program, and of things
that I don't. [REDACTED] it's hard to talk about these, er, things.
Please ignore this paragraph, and that paragraph marked with (*).)

[- -]

Michael Selik

unread,
Jun 28, 2016, 9:52:19 AM6/28/16
to
On Tue, Jun 28, 2016 at 9:26 AM Joseph Lee <joseph....@gmail.com>
wrote:

>
> -----Original Message-----
> From: Michael Selik
> Sent: Tuesday, June 28, 2016 6:16 AM
>
> MS: You should not. Use the first version, it's much better. Python
> for-loops are preferable to while-loops.
>
> JL: For the most part, for loops are better, but there are times when
> while loops are preferable such as when you don't know the size of the
> input beforehand.


Not knowing the number of elements is not a reason to prefer a while-loop.
A for-loop handles that quite well.

with open('example.txt') as f:
for line in f:
print(line)

We often loop over files without knowing how big a file is.

Michael Selik

unread,
Jun 28, 2016, 9:58:37 AM6/28/16
to
On Tue, Jun 28, 2016 at 9:34 AM BartC <b...@freeuk.com> wrote:

> On 28/06/2016 14:15, Michael Selik wrote:
> > On Tue, Jun 28, 2016 at 8:41 AM Elizabeth Weiss <cak...@gmail.com>
> wrote:
> >
> >> I do not understand the second code. What is counter?
> >>
> >
> > It looks like someone wanted to make a loop induction variable.
> > https://en.wikipedia.org/wiki/Induction_variable
>
> I don't know if that helps; I've never heard of an induction variable.
>

But you've seen them often in other programming languages?


> And according to the first example in that link, then 'word' in the OP's
> second example might be classed as an induction variable too!


The variable ``word`` was not being incremented/decremented by a fixed
amount, nor was it a linear function of another induction variable.


> Confusing.


Indeed. That's why Python's for-loops are preferable.

Steven D'Aprano

unread,
Jun 28, 2016, 11:20:30 AM6/28/16
to
On Tue, 28 Jun 2016 10:36 pm, Elizabeth Weiss wrote:

> Why do we use this code if we can use the simpler for loop?

Nobody with any sense would use the more complex while loop when the for
loop does the same thing.

While loops are great for loops where you don't know how many iterations
there will be but you do know that you want to keep going while some
condition applies:

while there is still work to be done:
do some more work


But if you know how many iterations there will be, use the for loop. Even if
you don't know the number ahead of time, if you have a list of them, use a
for loop:

for each job on my todo list:
do the job



There is a fashion, driven by "Learn Python The Hard Way", to teach people
the while loop first, because it's hard. I think that is stupid. It's like
teaching people to fly the Space Shuttle first, then saying "Ok, the Space
Shuttle is really complicated, but you can ride a bicycle instead" and then
teach them to ride a pushbike.





--
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

Jussi Piitulainen

unread,
Jun 28, 2016, 11:29:06 AM6/28/16
to
Steven D'Aprano writes:

> While loops are great for loops

:)

Thanks, I needed the laugh.

> where you don't know how many iterations there will be but you do know
> that you want to keep going while some condition applies:

(Just keeping a bit of context so it doesn't seem like I'm laughing at
the intended reading.)

Tim Chase

unread,
Jun 28, 2016, 1:23:37 PM6/28/16
to
On 2016-06-29 01:20, Steven D'Aprano wrote:
> While loops are great for loops where you don't know how many
> iterations there will be but you do know that you want to keep
> going while some condition applies:
>
> while there is still work to be done:
> do some more work

I find this particularly the case when the thing being iterated over
can be changed, such as a queue of things to process:

items = deque()
items.append(root_node)
while items:
item = items.popleft()
process(item)
items.extend(item.children)

Using a "for" loop balks if you try to change the thing over which
you're iterating.

But then, if you wrap up your "while" loop as a generator that yields
things, you can then use it in a "for" loop which seems to me like
the Pythonic way to do things. :-)

-tkc



Grant Edwards

unread,
Jun 28, 2016, 1:59:25 PM6/28/16
to
On 2016-06-28, Tim Chase <pytho...@tim.thechases.com> wrote:
> On 2016-06-29 01:20, Steven D'Aprano wrote:
>> While loops are great for loops where you don't know how many
>> iterations there will be but you do know that you want to keep
>> going while some condition applies:
>>
>> while there is still work to be done:
>> do some more work
>
> I find this particularly the case when the thing being iterated over
> can be changed, such as a queue of things to process:
>
> items = deque()
> items.append(root_node)
> while items:
> item = items.popleft()
> process(item)
> items.extend(item.children)

Yep, I often do something similar when processing a block of data
bytes comprising a sequence of "things" of varying number of bytes.

data = read_a_blob_of_bytes()
while data:
#figure out how long the first "thing" is
len = <some expression typically involving the first few bytes of 'data'>
handle_thing(data[:len])
data = data[len:]
> But then, if you wrap up your "while" loop as a generator that yields
> things, you can then use it in a "for" loop which seems to me like
> the Pythonic way to do things. :-)

Yea, I keep telling myself that, but I never actually do it.

--
Grant Edwards grant.b.edwards Yow! How do I get HOME?
at
gmail.com

Lawrence D’Oliveiro

unread,
Jun 29, 2016, 1:58:35 AM6/29/16
to
On Wednesday, June 29, 2016 at 1:30:04 AM UTC+12, BartC wrote:
> I don't know if that helps; I've never heard of an induction variable.

Perhaps it’s just a computability-theoretic way of saying “a variable whose value each time round the loop is a function of its value on the previous iteration”.

Ian Kelly

unread,
Jun 29, 2016, 11:36:31 AM6/29/16
to
On Tue, Jun 28, 2016 at 11:58 AM, Grant Edwards
<grant.b...@gmail.com> wrote:
> On 2016-06-28, Tim Chase <pytho...@tim.thechases.com> wrote:
>> On 2016-06-29 01:20, Steven D'Aprano wrote:
>>> While loops are great for loops where you don't know how many
>>> iterations there will be but you do know that you want to keep
>>> going while some condition applies:
>>>
>>> while there is still work to be done:
>>> do some more work
>>
>> I find this particularly the case when the thing being iterated over
>> can be changed, such as a queue of things to process:
>>
>> items = deque()
>> items.append(root_node)
>> while items:
>> item = items.popleft()
>> process(item)
>> items.extend(item.children)
>
> Yep, I often do something similar when processing a block of data
> bytes comprising a sequence of "things" of varying number of bytes.
>
> data = read_a_blob_of_bytes()
> while data:
> #figure out how long the first "thing" is
> len = <some expression typically involving the first few bytes of 'data'>
> handle_thing(data[:len])
> data = data[len:]
>> But then, if you wrap up your "while" loop as a generator that yields
>> things, you can then use it in a "for" loop which seems to me like
>> the Pythonic way to do things. :-)
>
> Yea, I keep telling myself that, but I never actually do it.

Here you go:

import collections

class MutableIterator:

def __init__(self, iterable):
self._stopped = False
self.replace(iterable)

def __iter__(self):
return self

def __next__(self):
if self._stopped:
raise StopIteration
while self._iterator or self._iterables:
if self._iterator:
try:
return next(self._iterator)
except StopIteration:
self._iterator = None
if self._iterables:
self._iterator = iter(self._iterables.popleft())
self._stopped = True
raise StopIteration

def clear():
self._iterables.clear()
self._iterator = None

def replace(self, iterable):
self._check_stopped()
self._iterables = collections.deque([iterable])
self._iterator = None

def append(self, item):
self.extend([item])

def extend(self, iterable):
self._check_stopped()
self._iterables.append(iterable)

def _check_stopped(self):
if self._stopped:
raise ValueError('Tried to mutate a stopped iterator')


# Example:

>>> mi = MutableIterator('bananas')
>>> for char in mi:
... if char == 'a':
... mi.extend(' yum')
... print(char, end='')
...
bananas yum yum yum

Steven D'Aprano

unread,
Jun 29, 2016, 7:59:40 PM6/29/16
to
On Thu, 30 Jun 2016 01:29 am, Ian Kelly wrote:

> On Tue, Jun 28, 2016 at 11:58 AM, Grant Edwards
> <grant.b...@gmail.com> wrote:
[...]
>>> But then, if you wrap up your "while" loop as a generator that yields
>>> things, you can then use it in a "for" loop which seems to me like
>>> the Pythonic way to do things. :-)
>>
>> Yea, I keep telling myself that, but I never actually do it.
>
> Here you go:
>
> import collections
>
> class MutableIterator:
[snip 8 methods and 33 lines of code]

> # Example:
>
>>>> mi = MutableIterator('bananas')
>>>> for char in mi:
> ... if char == 'a':
> ... mi.extend(' yum')
> ... print(char, end='')
> ...
> bananas yum yum yum

I'm curious what REPL you are using, because in the vanilla Python
interactive interpreter, the output if over-written by the prompt. That is,
what I see in Python 3.6 is:

py> nas yum yum yumpy>

unless I take steps to prevent that. See below.


But there's no need to go to such effort for a mutable iterator. This is
much simpler:

py> mi = list('bananas')
py> for char in mi:
... if char == 'a':
... mi.extend(' yum')
... print(char, end='')
... else: # oh no, the feared for...else!
... # needed to prevent the prompt overwriting the output
... print()
...
bananas yum yum yum
py>


This example shows two things:

(1) There's no need for a MutableIterator, we have list;

(2) Anyone who says that for...else without break is useless is wrong.

Tim Chase

unread,
Jun 30, 2016, 8:03:34 AM6/30/16
to
On 2016-06-30 09:59, Steven D'Aprano wrote:
> But there's no need to go to such effort for a mutable iterator.
> This is much simpler:
>
> py> mi = list('bananas')
> py> for char in mi:
> ... if char == 'a':
> ... mi.extend(' yum')
> ... print(char, end='')
> ... else: # oh no, the feared for...else!
> ... # needed to prevent the prompt overwriting the output
> ... print()
> ...
> bananas yum yum yum
> py>
>
>
> This example shows two things:
>
> (1) There's no need for a MutableIterator, we have list;

Convenient to know. I was fairly certain that this had failed for me
in past versions, but I went back to the oldest I have (2.4) and it
still works there. Might have to revisit some queuing code I have.

That said, it's not consistent across iterable container types. With

mi = set('bananas')
for char in mi:
if char == 'a':
mi.add('X')
print(char)
else:
print()

I get

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: Set changed size during iteration

If the list() meets your needs, then you're in luck. But just as
frequently, I want to use a set() or a dict() and have to write my
own wrapper around it.

-tkc

Ian Kelly

unread,
Jun 30, 2016, 9:05:14 AM6/30/16
to
On Wed, Jun 29, 2016 at 5:59 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> I'm curious what REPL you are using, because in the vanilla Python
> interactive interpreter, the output if over-written by the prompt. That is,
> what I see in Python 3.6 is:
>
> py> nas yum yum yumpy>
>
> unless I take steps to prevent that. See below.

I was just using the CPython 3.4 REPL with the default prompt. It
appended the prompt rather than overwriting, and I simply omitted it
in my message since it wasn't relevant to the example.

Ian Kelly

unread,
Jun 30, 2016, 9:11:29 AM6/30/16
to
On Wed, Jun 29, 2016 at 5:59 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> But there's no need to go to such effort for a mutable iterator. This is
> much simpler:
>
> py> mi = list('bananas')
> py> for char in mi:
> ... if char == 'a':
> ... mi.extend(' yum')
> ... print(char, end='')
> ... else: # oh no, the feared for...else!
> ... # needed to prevent the prompt overwriting the output
> ... print()
> ...
> bananas yum yum yum
> py>

One small difference with this approach is that iterators extended
onto the list are iterated over immediately rather than in sequence.
That could have implications in some scenarios.

jf...@ms4.hinet.net

unread,
Jun 30, 2016, 10:12:47 PM6/30/16
to
Steven D'Aprano at 2016/6/30 7:59:40AM wrote:
> py> mi = list('bananas')
> py> for char in mi:
> ... if char == 'a':
> ... mi.extend(' yum')
> ... print(char, end='')
> ... else: # oh no, the feared for...else!
> ... # needed to prevent the prompt overwriting the output
> ... print()
> ...
> bananas yum yum yum
> py>
>
>
> This example shows two things:
...
> (2) Anyone who says that for...else without break is useless is wrong.

Haha...you win.

By the way, I never said "else" without "break" is illegal or useless, I said it will cause confusion semantically, just like this(it reminds me the IOCCC:-):

import math
pass
import os
pass
import sys

Think of the "try ...except ...else ..." where the situation is similar but luckily it was mandatory.

--Jach

Veek M

unread,
Oct 27, 2016, 5:05:15 AM10/27/16
to
Elizabeth Weiss wrote:

> words=["hello", "world", "spam", "eggs"]
> counter=0
> max_index=len(words)-1
>
> while counter<=max_index:
> word=words[counter]
> print(word + "!")
> counter=counter + 1


while 0 < 10:
get 0'th element
do something with element
increment 0 to 1
(repeat)


words[0] gets the 0'th word (arrays/lists start at 0, not 1)
--------------------

That example of his is badly presented..

1. use i, x, y, z, count in that order for integers
2. do your dirty work in a function
3. keep loops clean and tidy
4. keep data far away from code
5. avoid " when ' does the trick
6. try to create black box functions - that work no matter what you
throw at them.. without sacrificing readability - programming is about
aesthetics and readability - quite artsy..

(I'm not an expert so.. some of this might be outright wrong)

words=['hello', 'world', 'spam', 'eggs']

def display(txt, decoration='!'):
message = str(txt) + str(decoration)
print(message)

i = 0
i_max = len(words) - 1

while i <= i_max:
word = words[i]
i += 1
display(word)

languages that don't have 'for' like C, will use 'while' - in python
'for' is preferred - faster, readable - especially for the example you
cited.

0 new messages