[Tutor] Skipping elements from inside generator loops
Jeff Shannon
jeff@ccvcorp.com
Thu, 01 Aug 2002 09:45:38 -0700
ibraheem umaru-mohammed wrote:
> [Scot W. Stevenson wrote...]
> <snip>...</snip>
> -|
> -| Somehow, it doesn't seem right to be able to change what amounts to a loop
> -| counter from the inside, even though it is useful here. [...]
>
> Hmmnn...This works for me: [...]
>
> >>> ...
> >>> black cat
> >>> white cat
> >>> grey cat
> >>> evil dog
> >>> fat cat
> >>> slow cat
> >>>
The point here was that the generator version (and the while-loop version) skipped the
"evil dog" entry. Thus, sounding the "alarm" allowed the felines to frolick unmolested.
To my mind, this greater control of the iteration is a very positive feature of
generators.
By the way, the effect *can* be created with a for-loop:
procession= ['black cat',
'white cat',
'grey cat',
'ALARM!',
'the evil dog',
'fat cat',
'slow cat']
cat_parade = procession[:]
for n in range(len(cat_parade)):
if cat_parade[n] == 'ALARM!':
clear = cat_parade.pop(n+1)
else:
print cat_parade[n]
-------- output is -----------
black cat
white cat
grey cat
fat cat
slow cat
------------------------------
Note that I am iterating over a copy of the list -- popping an item from the list
permanently modifies it, so I'm using a copy that I can throw away just in case the
original procession list is needed later. Also, pop() returns the item that was removed
from the list -- I'm assigning it to 'clear', an otherwise unused variable, because
otherwise the returned item is printed in the interactive shell. It would *not* be
printed in a direct execution, though -- this is strictly a feature of the interactive
shell that it will display unassigned results, the same feature that lets you do this sort
of thing:
>>> procession
['black cat', 'white cat', 'grey cat', 'ALARM!', 'the evil dog', 'fat cat', 'slow cat']
>>>
BTW, the reason that the original for-loop solution (adding 1 to the loop counter) didn't
work has to do with the *way* that for-loops work in Python. In C/C++ (and many other
languages), a for loop has a counter that starts at some number, and is incremented until
it reaches (or exceeds) some other number, but that's *not* what for-loops do in Python.
Instead, they take a list, and sequentially assign each element of the list to the "loop
counter" variable. This is pretty apparent when you're iterating over a list of strings,
but it's easy to forget when you're using an integer counter. The trick here is that
range(len(cat_parade)) actually creates a list of integers. When you added 1 to the
counter, you didn't modify that (unnamed) list of integers, and that list is all that the
for-loop looks at.
Hope that helps...
Jeff Shannon
Technician/Programmer
Credit International