0

I already have a solution to this Python code problem, but to try to be a better coder I am trying to better understand why the problem exists in the first place.

This works:

numbersA = [45, 22, 25, 73, 10, 33]

for i in range(len(numbersA)):
    numz = numbersA[i]
    if numz % 3 == 0:
        numbersA[i] = "buzz"
    if numz % 5 == 0:
        numbersA[i] = "fizz"
print(numbersA)

But this one:

numbersB = [45, 22, 25, 73, 10, 33]

for i in range(len(numbersB)):
    if numbersB[i] % 3 == 0:
        numbersB[i] = "buzz"
    if numbersB[i] % 5 == 0:
        numbersB[i] = "fizz"
print(numbersB)

gives an error:

Traceback (most recent call last):
  File "...", line 18, in <module>
    if numbersB[i] % 5 == 0:
TypeError: not all arguments converted during string formatting

My question is why?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61

3 Answers3

3

Let's look at the first iteration, i.e. i = 0. The number 45 is divisible by 3. So the first if is executed.

Inside it, you change the list in-place and now numbersB[0] = "buzz".

In the following line, you try to do if numbersB[0] % 5 == 0 which is now equivalent to if "buzz" % 5 == 0 which is a way to do string formatting, and this is why you get the error.

In Python it is rarely necessary to iterate over indices. In your case, enumerate will make your code correct and readable:

numbersB = [45, 22, 25, 73, 10, 33]

for i, num in enumerate(numbersB):
    if num % 3 == 0:
        numbersB[i] = "buzz"
    if num % 5 == 0:
        numbersB[i] = "fizz"
print(numbersB)
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
1

You have a problem in your code. If the first "if" is satisfied, the value at that location becomes a string, "buzz". Then, when the second "if" is checked, you're finding the remainder of a string and an integer, an operation that is not defined.

tino
  • 160
  • 6
  • rigth, try to use elif instead of the second if, s oif the first condition is matched it won't check the second – Leonardo Scotti Feb 24 '21 at 12:57
  • @LeonardoScotti but that will give the wrong output... – Tomerikoo Feb 24 '21 at 13:01
  • 1
    The operation `%` on a string and an integer **is** defined; try for example `'My favourite number is %d' % 23`. It obviously isn't want OP wants to do, of course, and the error here is caused by the string not having a format specifier like `%d` for the integer argument. – kaya3 Feb 24 '21 at 13:24
0

in code 2, you are modifing the existing list and then checking that modified value against % operation.

eg for value 45 list is, [45,1,2,3] say, now for condition 1 ie if value%3 is True so numberB[i]%3==0 ie 45%3==0 is true, so you are modifing it to 'fizz'.

numverB[0]='buzz' now list become ['fizz', 1,2,3..] now you are testing next condition ie % by 5, so 'buzz'%5 is giving error as mod operation not work on str.

In simple term, code 1 you are using a tempory data value which hold the index value in list, and testing the condition on that variable and then modifying the list value.

in code2, you directly checking against index value in list, and based on condition meet, modifying the internal list value, so due to, value which divided by 3 and 5, value first modified when it is divided by 3 to 'buzz' then when you testing value at that index (which become 'buzz' now not the int value) due to which you cant divide string by integer . so you are getting the error

numbersB = [45, 22, 25, 73, 10, 33]

for i in range(len(numbersB)):
    print('value at index {} is {} before any operation'.format(i,numberB[i]))
    if numbersB[i] % 3 == 0:
        numbersB[i] = "buzz"
        print('value at index {} is {} after dividing by 3 operation'.format(i,numberB[i]))
    if numbersB[i] % 5 == 0:
        numbersB[i] = "fizz"
        print('value at index {} is {} after dividing by 5 operation'.format(i,numberB[i]))
print(numbersB)

run above code, and you can see how the value changes in code2

sahasrara62
  • 10,069
  • 3
  • 29
  • 44