Python Referenced For Loop - python

I'm playing with for loops in Python and trying to get used to the way they handle variables.
Take the following piece for code:
a=[1,2,3,4,5]
b=a
b[0]=6
After doing this, the zeroth element of both b and a should be 6. The = sign points a reference at the array, yes?
Now, I take a for loop:
a=[1,2,3,4,5]
for i in a:
i=6
My expectation would be that every element of a is now 6, because I would imagine that i points to the elements in a rather than copying them; however, this doesn't seem to be the case.
Clarification would be appreciated, thanks!

Everything in python is treated like a reference. What happens when you do b[0] = 6 is that you assign the 6 to an appropriate place defined by LHS of that expression.
In the second example, you assign the references from the array to i, so that i is 1, then 2, then 3, ... but i never is an element of the array. So when you assign 6 to it, you just change the thing i represents.
http://docs.python.org/reference/datamodel.html is an interesting read if you want to know more about the details.

That isn't how it works. The for loop is iterating through the values of a. The variable i actually has no sense of what is in a itself. Basically, what is happening:
# this is basically what the loop is doing:
# beginning of loop:
i = a[0]
i = 6
# next iteration of for loop:
i = a[1]
i = 6
# next iteration of for loop:
i = a[2]
i = 6
# you get the idea.
At no point does the value at the index change, the only thing to change is the value of i.
You're trying to do this:
for i in xrange(len(a)):
a[i] = 6 # assign the value at index i

Just as you said, "The = sign points a reference". So your loop just reassigns the 'i' reference to 5 different numbers, each one in turn.

Related

How these python for loop and slicing working?

How this statement will work?
j for i in range(5)
Example:
x1=(j for i in range(5))
will yield five 4's when iterated. Why it will not yield 01234 like when we replace j with i.
How this statement working?
a = [0, 1, 2, 3]
for a[-1] in a:
print(a[-1])
0
1
2
2
Your first example is a generator expression (the parentheses are required, so the first version you show doesn't actually make sense). The generator expression repeatedly yields j, which is not defined in the code you show. But from your description, it already has the value 4 in the environment you were testing in, so you see that value repeatedly. You never use the i value, which is what's getting the values from the range.
As for your other loop, for a[-1] in a keeps rebinding the last value in the list, and then printing it.
A for loop does an assignment to the target you give it between for and in. Usually you use a local variable name (like i or j), but you can use a more complicated assignment target, like self.index or, as in this case, a[-1]. It's very strange to be rewriting a value of your list as you iterate over it, but it's not forbidden.
You never get 3 printed out, because each of the previous assignments as you iterated overwrote it in the list. The last iteration doesn't change the value that gets printed, since you're assigning a[-1] to itself.
Your first question raises error when iterating, as j is not defined. If you are getting any response from that, you probably have defined a value for j above your generator, which sounds to be 4 in your code.
About your second question:
when you have something like this:
for i in a:
...
Actually you are are doing this in each cycle: i=a[0], i=a[1], ....
When you write a[-1] in a, it is kind of equal to: a[-1]=a[0], a[-1]=a[1], ... and you are changing last element of a each time. So at the end, the last element of your list would be 2.

Can I not put a for loop inside a for loop like this? [duplicate]

I'm currently developing a program in python and I just noticed that something was wrong with the foreach loop in the language, or maybe the list structure. I'll just give a generic example of my problem to simplify, since I get the same erroneous behavior on both my program and my generic example:
x = [1,2,2,2,2]
for i in x:
x.remove(i)
print x
Well, the problem here is simple, I though that this code was supposed to remove all elements from a list. Well, the problem is that after it's execution, I always get 2 remaining elements in the list.
What am I doing wrong? Thanks for all the help in advance.
Edit: I don't want to empty a list, this is just an example...
This is a well-documented behaviour in Python, that you aren't supposed to modify the list being iterated through. Try this instead:
for i in x[:]:
x.remove(i)
The [:] returns a "slice" of x, which happens to contain all its elements, and is thus effectively a copy of x.
When you delete an element, and the for-loop incs to the next index, you then skip an element.
Do it backwards. Or please state your real problem.
I think, broadly speaking, that when you write:
for x in lst:
# loop body goes here
under the hood, python is doing something like this:
i = 0
while i < len(lst):
x = lst[i]
# loop body goes here
i += 1
If you insert lst.remove(x) for the loop body, perhaps then you'll be able to see why you get the result you do?
Essentially, python uses a moving pointer to traverse the list. The pointer starts by pointing at the first element. Then you remove the first element, thus making the second element the new first element. Then the pointer move to the new second – previously third – element. And so on. (it might be clearer if you use [1,2,3,4,5] instead of [1,2,2,2,2] as your sample list)
Why don't you just use:
x = []
It's probably because you're changing the same array that you're iterating over.
Try Chris-Jester Young's answer if you want to clear the array your way.
I know this is an old post with an accepted answer but for those that may still come along...
A few previous answers have indicated it's a bad idea to change an iterable during iteration. But as a way to highlight what is happening...
>>> x=[1,2,3,4,5]
>>> for i in x:
... print i, x.index(i)
... x.remove(i)
... print x
...
1 0
[2, 3, 4, 5]
3 1
[2, 4, 5]
5 2
[2, 4]
Hopefully the visual helps clarify.
I agree with John Fouhy regarding the break condition. Traversing a copy of the list works for the remove() method, as Chris Jester-Young suggested. But if one needs to pop() specific items, then iterating in reverse works, as Erik mentioned, in which case the operation can be done in place. For example:
def r_enumerate(iterable):
"""enumerator for reverse iteration of an iterable"""
enum = enumerate(reversed(iterable))
last = len(iterable)-1
return ((last - i, x) for i,x in enum)
x = [1,2,3,4,5]
y = []
for i,v in r_enumerate(x):
if v != 3:
y.append(x.pop(i))
print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y)
or with xrange:
x = [1,2,3,4,5]
y = []
for i in xrange(len(x)-1,-1,-1):
if x[i] != 3:
y.append(x.pop(i))
print 'i=%d, x=%s, y=%s' %(i,x,y)
If you need to filter stuff out of a list it may be a better idea to use list comprehension:
newlist = [x for x in oldlist if x%2]
for instance would filter all even numbers out of an integer list
The list stored in the memory of a computer. This deals with the pointer to a memory artifact. When you remove an element, in a by-element loop, you are then moving the pointer to the next available element in the memory address
You are modifying the memory and iterating thru the same.
The pointer to the element moves through the list to the next spot available.
So in the case of the Size being 5...enter code here
[**0**,1,2,3,4]
remove 0 ---> [1,**2**,3,4] pointer moves to second index.
remove 2 ---> [1,3,**4**] pointer moves to 3rd index.
remove 4 ---> [1,3]
I was just explaining this to my students when they used pop(1). Another very interesting side-effect error.
x=[1,**2**,3,4,5]
for i in x:
x.pop(1)
print(x,i)
[1, **3**, 4, 5] 1 at index 0 it removed the index 1 (2)
[1, **4**, 5] 3 at index 1 it removed the index 1 (3)
[1, 5] 5 at index 2 it removed the index 1 (4)
heh.
They were like why isnt this working... I mean... it did... exactly what you told it to do. Not a mind reader. :)

For Loop to determine lowest value of a list in python [duplicate]

This question already has answers here:
Can anyone explain me Python for loop (or iteration) algorithm
(4 answers)
Closed 2 years ago.
In the below, I have several questions. Firstly, why do we not define the starting value of i? In WHILE loops I came across this was the case. Secondly, I am finding it difficult to understand the "sequence" of what is happening. I understand that m = L[0] = 1 but the subsequent steps are not clear to me.
L=[1,2,4,-5,7,9,3,2]
m = L[0]
for i in L:
if i<m:
m = i
print(m)
For loops in python are really "for each" loops. Read it as "for each value 'i' in list 'L', do...".
i is not an index, it is the actual element in the list L.
So we set the initial minimum to just the first element of the list, and we say, for each element in our list, if there is a value smaller than our current minimum, we'll set our minimum to that element.
You don't want to define the starting value of i to make the program more variable to other cases. M is going to be the lowest value because that is what we are printing out. So if i is lower than m we want i to be m. The for loop goes through every number in the list.
L=[1,2,4,-5,7,9,3,2]
m = L[0] # start with m as the first value of your list which is 1.
for i in L: # for i in L means for i being consecutively 1 then 2 then 4 then -5 etc...
if i<m: # if i is less than m the starting point, give the value of i to m
# example if m = 1 and i =-3 after this condition m will take the value -3
m = i
print(m) # when you finish looping over all the examples print my m value
I would suggest writing the algorithm on a paper and you will see how easy it is.
m=1
loop
i=1
i<1? No.
go back to loop
i=2
i<1? No.
go back to loop
i=4
i<1? No.
go back to loop
i=-5
i<1? YES.
m = -5
go back to loop
.
.
.
The for loop proceeds via a form of hypothesis testing. First, we establish a loop invariant: something that remains true before and after each iteration. In this case, it is that m is the smallest value in the list that we have seen so far.
When we initialize m = L[0], it is true: having looked only at L[0], m is the smallest value we've seen so far.
Inside the loop, i takes on each value in the list exactly once. We compare it to m, and if i is indeed smaller, we use it as the new value of m. So after each iteration, m remains the smallest value seen so far.
Once the loop completes, having set i to each element in turn, we can conclude that m is not only the smallest value in L that we've seen so far, but it is the smallest value in L, period, because we have looked at every value in L.
The for loop is equivalent to the following while loop:
_index = 0
while True:
try:
i = L[_index]
except IndexError:
break
if i < m:
m = i
_index += 1
As you can see, we initialize _index to 0, and increment it explicitly at the end of each iteration. The for loop essentially keeps track of _index for us. i, on the other hand, is not initialized so much as it is derived from the current values of L and _index.
More generally, for loops don't manage repeated indexing operations, but are based on the iterator protocol. A for loop like
for i in L:
...
is roughly equivalent to
_itr = iter(L)
while True:
try:
i = next(_itr)
except StopIteration:
break
...
There is an easier way to do it without using a for loop so you can run your whatever code you want to run using the min() function for example in here:
L=[1,2,4,-5,7,9,3,2]
print(min(L)
I would recommend using something like this because its easier faster and runs smoother than the code in your question. The code in your question first runs a for loop that gets all the values out of the list and store them as i and runs threw them then it goes to the if statement which checks if the value which is i in this example is smaller than m which has the value of 1 then rewrites the variable m which was the value 1 to the value that is smaller than i which is -5 and as you see there this is a lot of function to run throw and that makes your code slower if the code consist of many lines.(Tip: always try using as minimum for loops or if statements as you can.)
your example:
L=[1,2,4,-5,7,9,3,2]
m = L[0]
for i in L:
if i<m:
m = i
print(m)

Python for loop?

I am having trouble understanding a Python for loop. For example, here is some code I've made while I'm learning:
board = []
for i in range (0,5):
board.append(["O"] * 5)
Don't worry about what the code does, I just don't understand what the "i" variable means.
Think of it as substitution.
range(0,5) is [0,1,2,3,4]. The for-loop goes through each element in the list, naming the element i.
for i in range(0,5):
# Starts with 0
print i # prints 0
# now goes back, goes through next element in list: 1.
Prints 0,1,2,3,4.
In your example, i is a placeholder. It is used simply just to loop something x amount of times (in this case, five as the length of range(0,5) is 5)
Also, have fun learning python at Codecademy (I recognise the task :p)
It's an iterator, you can see it as a bucket that stores the result of each iteration; the thing that adds confusion is the fact that it's simply unused in your script, this is another script with a "more involved" use of iterators.
fruits = ['banana', 'apple', 'strawberry', 'coconut', 'cherry']
for yup in fruits:
print(yup)
as you can see you can name it as you want, it's the syntax that makes that word an iterator.
It's an unused variable. Python syntax requires a variable in that position, but you don't do anything with it since you simply want to repeat an action 5 times.
Some people prefer the convention of naming an unused variable like this _:
for _ in range(5)
but this name can interfere with gettext.
In short, i refers to the current element in the list.
Your list is defined as: 0, 1, 2, 3, 4 and 5. Therefore i will iterate this list and assign itself to the next item, i is 0, next iteration i will be 1, next iteration i will be 2 etc.
Directly from python.org:
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence. For example (no pun intended)
words = ['cat', 'window', 'defenestrate']
for w in words:
print w, len(w)
Results in:
cat 3
window 6
defenestrate 12
http://docs.python.org/2/tutorial/controlflow.html
The for loop iterates over the given list of objects which is [0, 1, 2, 3, 4] obtained from range(0,5) and in every iteration, you need a variable to get the iterated value. That is the use i here. You can replace it with any variable to get the value.
for n in range(0, 5):
print n #prints 0, then 1, then 2, then 3,then 4 in each iteration
Another example:
for n in ('a', 'b', 'c'):
print n #prints a, then b, then c in each iteration
But in the code you have given, the variable i is not used. It is being used. just to iterate over the list of objects.
In c/java the for loop wiil be:
for(int i=0;i<=10;i++)
{
//for-loop-body
}
here for every iteration i will be incrementing +1 value till i reaches 10, after that it comes out of loop.
In same way,in python the for loop looks like:
for i in range(0,10):
//for-loop-body
here i performs same operation and i is just a variable to increment a value.

Why does Python skip elements when I modify a list while iterating over it?

I'm currently developing a program in python and I just noticed that something was wrong with the foreach loop in the language, or maybe the list structure. I'll just give a generic example of my problem to simplify, since I get the same erroneous behavior on both my program and my generic example:
x = [1,2,2,2,2]
for i in x:
x.remove(i)
print x
Well, the problem here is simple, I though that this code was supposed to remove all elements from a list. Well, the problem is that after it's execution, I always get 2 remaining elements in the list.
What am I doing wrong? Thanks for all the help in advance.
Edit: I don't want to empty a list, this is just an example...
This is a well-documented behaviour in Python, that you aren't supposed to modify the list being iterated through. Try this instead:
for i in x[:]:
x.remove(i)
The [:] returns a "slice" of x, which happens to contain all its elements, and is thus effectively a copy of x.
When you delete an element, and the for-loop incs to the next index, you then skip an element.
Do it backwards. Or please state your real problem.
I think, broadly speaking, that when you write:
for x in lst:
# loop body goes here
under the hood, python is doing something like this:
i = 0
while i < len(lst):
x = lst[i]
# loop body goes here
i += 1
If you insert lst.remove(x) for the loop body, perhaps then you'll be able to see why you get the result you do?
Essentially, python uses a moving pointer to traverse the list. The pointer starts by pointing at the first element. Then you remove the first element, thus making the second element the new first element. Then the pointer move to the new second – previously third – element. And so on. (it might be clearer if you use [1,2,3,4,5] instead of [1,2,2,2,2] as your sample list)
Why don't you just use:
x = []
It's probably because you're changing the same array that you're iterating over.
Try Chris-Jester Young's answer if you want to clear the array your way.
I know this is an old post with an accepted answer but for those that may still come along...
A few previous answers have indicated it's a bad idea to change an iterable during iteration. But as a way to highlight what is happening...
>>> x=[1,2,3,4,5]
>>> for i in x:
... print i, x.index(i)
... x.remove(i)
... print x
...
1 0
[2, 3, 4, 5]
3 1
[2, 4, 5]
5 2
[2, 4]
Hopefully the visual helps clarify.
I agree with John Fouhy regarding the break condition. Traversing a copy of the list works for the remove() method, as Chris Jester-Young suggested. But if one needs to pop() specific items, then iterating in reverse works, as Erik mentioned, in which case the operation can be done in place. For example:
def r_enumerate(iterable):
"""enumerator for reverse iteration of an iterable"""
enum = enumerate(reversed(iterable))
last = len(iterable)-1
return ((last - i, x) for i,x in enum)
x = [1,2,3,4,5]
y = []
for i,v in r_enumerate(x):
if v != 3:
y.append(x.pop(i))
print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y)
or with xrange:
x = [1,2,3,4,5]
y = []
for i in xrange(len(x)-1,-1,-1):
if x[i] != 3:
y.append(x.pop(i))
print 'i=%d, x=%s, y=%s' %(i,x,y)
If you need to filter stuff out of a list it may be a better idea to use list comprehension:
newlist = [x for x in oldlist if x%2]
for instance would filter all even numbers out of an integer list
The list stored in the memory of a computer. This deals with the pointer to a memory artifact. When you remove an element, in a by-element loop, you are then moving the pointer to the next available element in the memory address
You are modifying the memory and iterating thru the same.
The pointer to the element moves through the list to the next spot available.
So in the case of the Size being 5...enter code here
[**0**,1,2,3,4]
remove 0 ---> [1,**2**,3,4] pointer moves to second index.
remove 2 ---> [1,3,**4**] pointer moves to 3rd index.
remove 4 ---> [1,3]
I was just explaining this to my students when they used pop(1). Another very interesting side-effect error.
x=[1,**2**,3,4,5]
for i in x:
x.pop(1)
print(x,i)
[1, **3**, 4, 5] 1 at index 0 it removed the index 1 (2)
[1, **4**, 5] 3 at index 1 it removed the index 1 (3)
[1, 5] 5 at index 2 it removed the index 1 (4)
heh.
They were like why isnt this working... I mean... it did... exactly what you told it to do. Not a mind reader. :)

Categories

Resources