How these python for loop and slicing working? - python

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.

Related

for in loop over list (with +=) coding beginner

a = [1,2,3]
for num in a:
a = a + [num]
print(a)
>>>[1,2,3,1,2,3]
a = [1,2,3]
for num in a:
a += [num]
print(a)
>>>
The first code works as expected, so I assume the below code will work the same, but it didn't print anything. Not even a Error message.
Question:
I did some research in stackoverflow on the use of +=, but still got confused on what's the difference between the add and iadd
In the first case, you are rebinding the name a to a new value, so the variable a before the loop is not the same object as the variable a inside and after the loop. The loop is able to iterate on the original value of a.
But in the second case, you are not rebinding the name. a is the same object throughout the code. And so the loop iterates over a list that grows endlessly bigger.

Reverse accessing a list in python

a=[0,1,2,3]
for a[-1] in a :
print a[-1]
This Program gives me an output
0
1
2
2
I am not able to decode it. I was expecting it to print the list in reverse direction. or at least print 3 alone. Can someone help me to understand this output
at each iteration a[-1] (the last element of a) is assigned a value of a (the list becomes [0,1,2,0] then [0,1,2,1] then [0,1,2,2])
a=[0,1,2,3]
for a[-1] in a :
print(a[-1])
It "works" until the end (although forward, not reversed), where the last iteration yields the last iterated upon value: 2
Now of course if you just want to iterate a list backwards:
for i in reversed(a):
print(i)
reversed(a) is better than a[::-1] here because it doesn't create a list just to iterate on it.
You can use
for x in a[::-1]:
print x
Which goes "reads" the list in reverse order, one element at a time. A list is implicitly "read" like a[::1]. If you'd like to "read" a list in reverse order but every second element you could use a[::-2] which would give you [3, 1].
Or you can use
for x in reversed(a):
print x

Infinite loops using 'for' in Python [duplicate]

This question already has answers here:
Is there an expression for an infinite iterator?
(7 answers)
Closed 5 years ago.
Why does this not create an infinite loop?
a=5
for i in range(1,a):
print(i)
a=a+1
or this
for i in range(1,4):
print(i)
i=i-1
or this
for i in range(1,4):
print(i)
i=1
Is there any way we can create infinite loops using a for loop? I know there is the while loop for that but I was just curious.
range is a class, and using in like e.g. range(1, a) creates an object of that class. This object is created only once, it is not recreated every iteration of the loop. That's the reason the first example will not result in an infinite loop.
The other two loops are not infinite because, unlike the range object, the loop variable i is recreated (or rather reinitialized) each iteration. The values you assign to i inside the loop will be overwritten as the loop iterates.
Consider a for loop:
for item in iterable:
print(item)
The idea is that as long as iterable is unchanged, we will loop through each and every item inside iterable once. For example,
for item in [3, 2, 1, 666]:
print(item)
will output 3 2 1 666. In particular, we find that range(1, 4) is a easy way to represent an iterable [1, 2, 3]. Thus,
for i in range(1, 4):
print(i)
will output 1 2 3.
Example 1
a=5
for i in range(1,a):
print(i)
a=a+1
In this case, range(1,a) is evaluated once, when the loop begins.
Example 2
for i in range(1,4):
print(i)
i=i-1
In this case, i is reevaluated every loop, before executing the print and i=i-1 statements within the body of the loop.
Example 3
for i in range(1,4):
print(i)
i=1
Just like Example 2, i is reevaluated every loop.
You can't, in this case, update the iterator that your for loop is looping over.
The range in for i in range(a): is actually a function - it takes a value, a, and returns an object that contains the values that it will loop through. Once you've built that object you can change the input variable as much as you'd like, and that object won't change.
Imagine if we made our own similar function called my_range that generates a list (whereas the built in range function generates a range):
def my_range(end):
my_list = []
for i in range(end):
my_list.append(i)
return my_list
Now if we were to use our new function, like so:
a = 4
for i in my_range(a):
print(i)
a += 1
It'd be obvious that we can't update the list object that we're looping over by changing a, because the list that we're looping over has already been made, and isn't being remade on every loop.
Can you make an infinite loop in python? Yes, just add a new entry to the object that you're looping through, e.g.:
my_list = [0]
for i in my_list:
print(i)
my_list.append(i+1)
Now we're updating the object that we're looping over.
for loops and the range(..) object
If you write for i in range(..): Python does not translate this into something like for(int i = 0; i < n; i++) (in the C-programming language family).
Furthermore the range object is constructed once, before the for loop. The range(..) object, does not know which variables have been used to construct it. Once constructed, the range is fixed.
It sees range(..) as an iterable object, and each iteration, it takes the next item the iterable yields. So whether you set the variable or not in the for loop, has no effect for the next iteration.
In python-2.x, range(..) is not a specific object, but a call to construct a list. So if you call range(10) (without the for loop), you get [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].
Why it does not work?
So then why does the examples do not work?
a=5
for i in range(1,a):
print(i)
a=a+1
Here we construct range(..) once. After that, the variables based on which it was constructed can change, since the range(..) object does change anymore. Incrementing a thus will not mean the range object will get larger.
for i in range(1,4):
print(i)
i=i-1
The for loop each time takes the next item of the iterable. So if we first have collected 1 from the range loop, the next iteration, we collect 2. This is regardless what the value of i is.
for i in range(1,4):
print(i)
i=1
For the very same reason: for does not take into account the previous value of i. It only fetches the next item the iterable (here range(..) yields). Since range(..) is fixed, it will simply feed the for loop the next item.
Emulating an infinite loop
So we need to construct an iterable that keeps yielding elements. A way to do this is itertools.count:
from itertools import count
for i in count():
# ...
pass
Or in case you are not interested in any value, we can use repeat as well:
from itertools import repeat
for _ in repeat(None):
# ...
pass
range copies the parameters given to it for internal use. So changes to those afterwards have no effect. Same as with the loop variable, which is only created from the internal values every time.
That's different though if you use a mutable object like a list to iterate over:
a = [1,2,3]
for i in a:
a.append(i)
This loop will indeed run infinitely.
Because a range is either a list (Python2) or a range object both of which are finite. That range is created once before the loop starts. Your loop variable is assigned the next element of the range at the beginning of each iteration, regardless of what you assign it later in the loop body. You need an infinite iterator for an infinite for loop, e.g. itertools.cycle:
from itertools import cycle
for x in cycle(range(5)):
# endless

Python Referenced For Loop

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.

Strange python for syntax, how does this work, whats it called?

print max(3 for i in range(4))
#output is 3
Using Python 2.6
The 3 is throwing me off, heres my attempt at explaining whats going on.
for i in range(4) makes a loop that loops 4 times, incrementing i from 0 to 3 at the start of each loop. [no idea what the 3 means in this context...] max() returns the biggest iterable passed to it and the result is printed to screen.
3 for i in range(4) is a generator that yields 3 four times in a row and max takes an iterable and returns the element with the highest value, which is, obviously, three here.
This evaluates to:
print max([3,3,3,3])
... which is an elaborate way to say print 3.
expr for x in xs is a generator expression. Typically, you would use x in expr. For example:
[2*i for i in range(4)] #=> [0, 2, 4, 6]
It can be rewritten as:
nums = []
for i in range(4):
nums.append(3)
print max(nums) # 3! Hurrah!
I hope that makes its pointlessness more obvious.
The expression:
print max(3 for i in range(4))
is printing the result of the max() function, applied to what is inside the parentheses. Inside the parentheses however, you have a generator expression creating something similar to an array, with all elements equal to 3, but in a more efficient way than the expression:
print max([3 for i in range(4)])
which will create an array of 3s and destroy it after it is no longer needed.
Basically: because inside the parentheses you will create only values that are equal, and the max() function returns the biggest one, you do not need to create more than one element. Because with the number of elements always equal to one, the max() function becomes not needed and your code can be effectively replaced (at least in the case you have given) by the following code:
print 3
That is simply all ;)
To read more about differences between comprehension and generator expression, you can visit this documentation page.

Categories

Resources