+ 3
Why Answer is not 3 3 3 3?
What is the output of this code? a=[0,1,2,3] for a[-1] in a: print(a[-1])
29 Answers
+ 4
ok, idk if you care but I wasn't really satisfied with my previous answer, so I've done some deep digging and here's what's happening to cause the 0 1 2 2 pattern:
for X in Y: -- takes each element in Y and creates an "iterable" object (structurally like a list, but functionally distinct) with each of those same elements in it. Then it takes the next element of the iterable, assigns it to X, and performs the operations specified in the for loop. Repeat until the next element doesn't exist.
So, what "for a[-1] in a" does is:
1. make an iterable containing a[0], a[1], a[2], a[3]
2. set a[-1] = a[0] (which is 0)
3. perform print(a[-1]) (prints 0)
4. set a[-1] = a[1] (which is 1)
5. perform print(a[-1]) (prints 1)
6. set a[-1] = a[2] (which is 2)
7. perform print(a[-1]) (prints 2)
8. set a[-1] = a[3] (which is still 2, from step 6)
9. perform print(a[-1]) (prints 2)
result: 0 1 2 2
So if you care, that's why it failed in the precise way that it did.
+ 3
Orin Cook Yes. Pls check out another example of a Python for loop altering the iterator, and see how this immediately affects each iteration.
https://code.sololearn.com/cNJHu2llACej/?ref=app
+ 2
Hey well you started the for loop with the last entry excluded so your output will be 0,1,2,2. What you try to do ?
If you wanna try access the last element than you need a[3] instead[-1]
+ 1
when you iterate through a list like this, use a fresh, generic variable for your index. I'm not sure what you thought you were doing there, but in the line:
for a[-1] in a:
just replace a[-1] with a new, unused variable name. it can he x, it can be i, or it can even be literally_anything_else, as I typed above, and it'll work.
btw, S3R43o3 : python allows negative indexing of lists to count backwards from the end, so a[-1] is valid. I hate it, but it's valid.
+ 1
Dadaxon Xudayberganov 🇺🇿🇺🇿🇺🇿 Orin Cook
you're modifying a as you iterate through it.
iterating through a and assigning the value to a[-1] at each pass.
you can introspect what's happening:
a=[0,1,2,3]
print('before: ', a)
for a[-1] in a:
print('inside: ', a)
print('a[-1]: ', a[-1])
print('final: ', a)
Normally, a for-in loop in Python would not modify the list, but putting the list itself as the iterator changes the behavior since the values are assigned back to the list.
So I would probably say it's a case of self-reassignment.
+ 1
Orin Cook In the case of lazy evaluation, shouldn't the result be [0, 0, 1, 2, 3]?
+ 1
Dadaxon Xudayberganov 🇺🇿🇺🇿🇺🇿
if you want 3 3 3 3 use
a = [0,1,2,3]
for _ in a:
print(a[-1], end=' ')
+ 1
Emerson Prado no, because index is the *contents of* the nth element in the last. In fact it would probably throw an error if it were eager (python doesn't let you do that, at least not in the Playground), but since it's lazy, by the time it checks the final value it's already 2, not 3. So it changes [2+1] on the final iteration.
That said, you did give me an idea for making it more obvious that it's lazy, so go look at the revised code above. Remove the index != 4 condition if you wanna see it go forever lol
0
for literally_anything_else in a:
0
I don't understand 😞
0
PS: my understanding is that it actually generates the iterable lazily, ie it doesn't look for the next element until it has to. I *believe* this is the real underlying reason why a[3] gives 2 instead of 3, but I couldn't totally nail down a concrete answer to that, and it's also possible that it's using memory addresses from the original list behind the scenes, which would produce the same result.
0
Dadaxon Xudayberganov 🇺🇿🇺🇿🇺🇿 Why are you iterating on a list using an item from the same list as loop variable?
0
Emerson Prado It is not my example. It is from Solo learn examples
0
Thanks everyone
0
Orin Cook i didnt say thats not valid i just say that dosent print out 3 3 3 3 😉
0
That sounds good until you dig into how iter() is implemented under the hood. When you do "X in Y," it doesn't actually use Y itself but an explicit iterable-type object copied from Y.
Still, if you're 100% sure it's not lazy, that tells us that it's copying Y by reference rather than value, which is an interesting thing to know.
0
that doesn't actually demonstrate anything because your iterator is constructed from the iterable range(), not from the list.
ps range() is explicitly implemented lazily, so double the non-demonstration
0
ok, so if I did this right I think this actually proves that iter() *IS* lazy:
https://code.sololearn.com/cmecKbEa7uh4/?ref=app
0
Mirielle that is incorrect, go look up iter(), __iter__, and __next__. Creating a new iterable object is exactly how it's implemented under the hood.