[Tutor] Strange modulus problem
Kirby Urner
urnerk@qwest.net
Thu, 11 Oct 2001 20:22:57 -0700
>
>Why doesn't '5' fail the if test and get removed? If I modify
>the code so that it prints the modulus of each item, 5 correctly
>evalutates to '1'. What gives?
>
>- Chris
This has to do with iterating over the object you're
also modifying.
The code below works because it iterates over a copy
of factor_range (the effect of putting [:] after it):
>>> def factors(n):
factor_range = range(1, n + 1)
for item in factor_range[:]:
if n % item:
factor_range.remove(item)
return factor_range
>>> factors(6)
[1, 2, 3, 6]
>>> factors(20)
[1, 2, 4, 5, 10, 20]
(Note also that n%item is true if non-zero, so you
don't really need the additional >0).
In the your way of doing it, you don't actually get to
test all the numbers in the range, because you yank an
offender out of the line-up, shortening the list, so
when the loop comes around and it iterates to the
"next" item, it's hitting against a foreshortened list,
meaning it skips over a value you wish it hadn't.
You can study this behavior by inserting a line that
prints the item being tested:
>>> def factors(n):
factor_range = range(1, n + 1)
for item in factor_range: # not a copy
print item # debug print
if n % item:
factor_range.remove(item)
return factor_range
>>> factors(10)
1
2
3
5
6
8
10
[1, 2, 4, 5, 7, 9, 10]
You see that 4 wasn't tested, because the program yanks
3 (not a factor), and so the next candidate it hits if 5.
Likewise, 7 and 9 sneak through.
This is a common programming error in Python and you're
lucky to stumble across it in such an illuminating
manner. It's very good to make mistakes of this kind
-- very text book. You have a promising career as a
Pythoneer ahead of you (pardon the fortune cookie).
Kirby