# FAQ: Learn Python - Lists and Functions - Iterating over a list in a function

What am I doing wrong:

def total(numbers):
result = 0
for item in numbers:
item + result
return result

Item + result is not a legal operation.

If you meant to increment result variable then you need to check the item + result and redo it so it reflects something like

``````x += y
``````

so that when you return result its value is updated.

@psmilliorn do you know when to use ‘+’ versus using ‘+=’?

``````a = 0
b = 1
a = a + b
``````

That is one example. You can also just do.

``````a = 0
b = 1
a += b
``````

Hey guys, I’m really confused on the whole for loops being used in-conjunction with lists, don’t really feel previous lessons have explained it enough for me to understand. I was wondering if anyone could help provide an idiot proof explanation!!! Here is the code I have used:

``````n = [5,8,2]
def total(numbers):
for n in numbers:
result = 0
result += n
return result
print total(n)
``````

If I do the following then I get a result of 2:

``````   result += n
return result
``````

When I run this code I get the value 5, and I don’t know why, however if I remove the function and just use a for loop like so:

``````n = [5,8,2]
for numbers in n:
result = 0
result += numbers
print result
``````

The code only prints out the last value in the list ( I know that the word numbers and n are swapped between the first and second example, and that the result += changes between n and numbers also, this is because if I don’t then on the second example I get an error saying int object is not iterable, I don’t entirely know what this means either.)

if I indent the print like so:

``````result += numbers
print result
``````

Then it ends up printing all 3 numbers ie:
5
8
2

If anyone could help explain what is happening and what I am doing wrong, I would me much grateful!!!

Please have a look at How do I format code in my posts? which explains how to keep the code formatting and for Python the indentation which is very important.

If I’m not mistaken your first code has the `return` statement inside the loop. As soon as `return` is executed the function stops at the point and returns the result to the original caller. If it’s in a loop this means your loop probably finishes too soon.

This is also what makes your `print` repeat three times. If you review the steps your loop takes you can probably also see why the output is `5`, `8`, `2` instead of the expected total.

Try playing around this until it makes sense .

But I don’t know what steps my for loop takes, to get the result that it does, which is why I was wondering if anyone could help provide an explanation as to what I am doing wrong, or how to do it correctly?

I thought I had, your problem is that you `return` too early (and reset your counter too). Things inside the loop will run on every iteration of the loop. Think very carefully about what you actually want to repeat in this loop.

Can you explain what the error message object is not iterable?
Can you also explain if below is done:

``````my_list = [1,9,3,8,5,7]
total = 0
for number in my_list:
total += number
print total
``````

Then it prints out:
1
10
13
21
26
33
but if the print statement is not indented, the same as previous line above, it just prints out 33, is it because if its indented, it’s saying for every item in the list, add that item to total then print the current total, and repeat this process, but if that is correct, if the print statement is unindented it just prints the whole total: 33, can you explain this please?

If I do the following:

``````my_list = [1,9,3,8,5,7]
total = 0
for number in my_list:
total += number
``````

Then I get an error saying total is not defined, but if I do the below, then I get 33? why if I declare `total = 0`, outside the function it works, but if I don’t, I get an error?

``````my_list = [1,9,3,8,5,7]
total = 0
for number in my_list:
total += number
``````

The first code is correct, except you then try to use `total` outside the function as well:

``````print add_my_list(total)
``````

`total` has a local scope (only exists within the function)

when you call the function, I think you want to provide `my_list` as argument

about the second code sample: bad idea, you have a global total, which means multiple function calls will add to the total of earlier function calls

1 Like

Surely if ` print add_my_list(total)` is carried out it is part of the function, as it is set to zero below the line ` def add_my_list` ? When I do `print add_my_list(my_list)` it does return 33 (which is correct), but how why does this work if when I created the function I used the argument total ie, `def add_my_list(total)`?

no, functions are a set of instructions which are executed later. Kind of like a todo-list, you can make a todo list (defining functions), but actually executing the tasks on the todo-list (calling functions) can happen later

parameters like total here:

``````def add_my_list(total):
``````

act as placeholder until the parameters receive their actual values from arguments at function call.

So I understand that a function is a way of creating a to-do list, which then can be called later, but if I understand what you’re saying correctly about place holders , in the example: ` def add_my_list(total)` total is just a placeholder value, which means it hasn’t actually been defined? If that is the case then how come, when you type `def add_my_list(total)` the total is a place holder for an argument, and you then set it to zero ie:

``````def add_my_list(tottal)
total = 0
``````

how come if you then were to call the function with total as the argument it wont work?
ie: `print add_my_list(total)` since you have defined total by setting it to zero and then incorporating it into a for loop, add if total is just a place holder, what’s the point in using place holder’s if you can just use the name of the variable you want to pass as the argument?
ie:

``````my_list = [1,9,3,8,5,7]
total = 0
for number in my_list:
total += number
``````

Which still works and prints the correct result 33.

Think of it more like this…

``````def add_my_list(a_list):    # a_list is the parameter
total = 0
for number in a_list:
total += number

my_list = [1,9,3,8,5,7]
print add_my_list(my_list)  # my_list is the argument
``````

Parameters are names in the local namespace that refer to positional arguments. One parameter, one argument. The argument is an object, the parameter is the name that object will be known by in local scope. It gets messy when we give the argument (object) and the parameter the same name, especially if we don’t fully understand scope.

It would appear in this conversation that one is clear on the scope in which `total` is defined (as well as `a_list`) which explains why we cannot access it outside of the function.

1 Like

What is wrong with using the same name for the parameter and argument? Surely it just makes things easier to follow especially if you’re looking at someone else’s code? I am confused in what you mean when you say ‘the scope in which `total` is defined’ I understand that in order to pass an argument, within a function you need to declare one ie `def add_my_list(total` where `total` is just a place holder, but I still don’t understand why if when `total` is set to zero it hasn’t been defined? and why you can’t use `my_list` as the argument in the function?

It doesn’t make sense, and it does not make it easier to read. Remember that this function is a utility that can be called from anywhere in the program on any list object. Keep the names to the objects discrete, and the names of the parameters generic.

Parameters are not placeholders. They are locally defined variables that indicate a required positional argument.

In what scope is `target` defined?

But it is used as the argument (the function call).

``````def foo (variable):  # parameter is a local generic name
pass

print (foo(object))  # argument is an object in outer scope
``````

It would appear in this conversation that one is clear on the scope in which `total` is defined (as well as `a_list` ) which explains why we cannot access it outside of the function.

In what scope is `target` defined?

But I don’t know what a scope is, so I am not clear on how it is defined, if you could please explain what you mean by scope, so I can understand what you’re trying to say. I would also like to ask in what way is it not clear to use the same name for the argument and parameter. When I do the following:

` list_1 =[1, 2, 3] def add_list(list_1): total = 0 for i in list_1: total += i return total print add_list(list_1)`

`print times_list(list_1) def times_list(list_1): total = 0 for i in list_1: total += i *2 return total print times_list(list_1)`

Both do as expected ie the first prints 6 and the second 12. I am also confused about when using the for loop to `total += i`, if I do `+= [i]` or `+= list_1` I get the following error: unsupported operand type(s) for +=: ‘int’ and ‘list’, if I do: `+= list_1[i]` I get: list index out of range, but if you compare that to using the range method, the range method only works when doing `+= numbers [i]`. Can you kindly explain what these mean and why I get them, and why when using the range method the `+=` is different? The last question I have is when using the range method I’ve noticed that if I do either `for i in range(len(numbers)):` or `for i in range(0,len(numbers)):` I get the same outcome, but the solution writes it as the former, why is this?

There is some mention of Scope in the Learn Python 3 course, and another more in depth look at in the Learn Intermediate Python 3 course. Are you a Pro or Student subscriber? If so, track down that unit in the course.

Briefly, there are four kinds of scope in Python.

• built-in
• global
• enclosing
• local

From the bottom, look up. The scopes above are accessible to the scopes below, but not the other way around (without some help). As we can see, all scopes are accessible from `local` scope. That is the scope, or namespace inside a function.

``````def foo():
# local scope
pass
``````

When a variable is declared within the function, it can only be accessed from within that function. Any variables outside of the function remain accessible from within it.

``````def bar():
# enclosing scope
pass
def foo():
# local scope
pass
``````

Variables declared in `bar` are accessible to `foo` but not the other way around. From the point of view of `foo`, the variables in `bar` are seen as non-local. In order for `foo` to be able to mutate those variables it will require a binding declaration…

``````def bar():
# enclosing scope
b = 40
def foo():
# local scope
nonlocal b
b += 2
``````

Outside of a function we are in `global` scope. From this namespace we can access (call) all direct functions, but none of the enclosed functions. We can call `bar()`, but not `foo()`. All global variables can be accessed from anywhere except the `built-in` namespace. If our function is expected to mutate a global variable, then just as we declared `b` to be non-local in `foo()`, we would need to declare a binding.

``````a = 73
def bar():
global a
a -= 31
``````

Lastly we have the built-in namespace which is where Python resides.

Anyway, I hope you can track down that unit and give it a read.

``````+= i
``````

and

``````+= [i]
``````

are two completely different operations. The first one can only be performed on a static number, such as,

``````b = 40
b += i
``````

which will increase `b` by `i`.

``````b = 
b += [I]
``````

will append `i` to the list, not add it to 40. (see list.extend()).

The multiplication function implies we are to double each value in the list, which does not involve keeping a running tally (so no `total`).

``````for x in list_1:
``````

won’t work since we cannot mutate the list.

``````for i in range(len(list_1):
list_1[i] *= 2
``````

will work since we are iterating the range, not the list. Rule of thumb, never mutate a list you are iterating. Python simply won’t allow it.

Notice we touch on your range question, above. When the start index is omitted, Python defaults to zero, so whether we include the `0` or not, it is still the starting value. We need that positional argument so that we can start wherever we wish.

``````for i in range(3, int(n ** 0.5) + 1, 2):
``````

Above the start value is `3`, the end value is `int(n ** 0.5) + 1, and the step, or *stride* value is `2`. Recall that a range does not include the uppermost value.

Of note

`+=` can also be used on strings to perform in-place concatenation (much like the list concatenates with another list).

`*=` can also be used on strings to perform repetition.

``````>>> a = '*'
>>> a *= 8
>>> a
'********'
>>>
``````

and similarly, on lists…

``````>>> a = ['0']
>>> a *= 8
>>> a
['0', '0', '0', '0', '0', '0', '0', '0']
>>>
``````

The other arithmetic assignment operators can only be used on numbers or bits. We cannot subtract from a string or list object. Neither can we divide, etc.

Lastly, with regard to range, we can set the direction in reverse by starting from the right side and ending on the left (remember the last value is excluded so it you wish to end on `0`, it must be set to `-1`) and using a negative stride value…

``````>>> list(range(10, -1, -1))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>>
``````