Why can I use a list index as an indexing variable in a for loop? [duplicate] Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!Why are arbitrary target expressions allowed in for-loops?Are for-loop name list expressions legal?Why is using a list subscription allowed in a for loop?How does database indexing work?Finding the index of an item given a list containing it in PythonAccessing the index in 'for' loops?Understanding Python super() with __init__() methodsHow do I sort a dictionary by value?How to make a flat list out of list of listsHow do I pass a variable by reference?Loop through an array in JavaScriptHow do I list all files of a directory?Why is printing “B” dramatically slower than printing “#”?

What does the "x" in "x86" represent?

Does classifying an integer as a discrete log require it be part of a multiplicative group?

Around usage results

Is there a holomorphic function on open unit disc with this property?

Can a new player join a group only when a new campaign starts?

How come Sam didn't become Lord of Horn Hill?

Trademark violation for app?

8 Prisoners wearing hats

Has negative voting ever been officially implemented in elections, or seriously proposed, or even studied?

How would a mousetrap for use in space work?

Withdrew £2800, but only £2000 shows as withdrawn on online banking; what are my obligations?

Did MS DOS itself ever use blinking text?

Why are there no cargo aircraft with "flying wing" design?

Why aren't air breathing engines used as small first stages

Wu formula for manifolds with boundary

Why are both D and D# fitting into my E minor key?

Would "destroying" Wurmcoil Engine prevent its tokens from being created?

Is "Reachable Object" really an NP-complete problem?

Is it fair for a professor to grade us on the possession of past papers?

What is the meaning of the simile “quick as silk”?

Delete nth line from bottom

What is this building called? (It was built in 2002)

How to Make a Beautiful Stacked 3D Plot

Do I really need recursive chmod to restrict access to a folder?



Why can I use a list index as an indexing variable in a for loop? [duplicate]



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!Why are arbitrary target expressions allowed in for-loops?Are for-loop name list expressions legal?Why is using a list subscription allowed in a for loop?How does database indexing work?Finding the index of an item given a list containing it in PythonAccessing the index in 'for' loops?Understanding Python super() with __init__() methodsHow do I sort a dictionary by value?How to make a flat list out of list of listsHow do I pass a variable by reference?Loop through an array in JavaScriptHow do I list all files of a directory?Why is printing “B” dramatically slower than printing “#”?



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








76
















This question already has an answer here:



  • Why are arbitrary target expressions allowed in for-loops?

    4 answers



  • Are for-loop name list expressions legal?

    2 answers



  • Why is using a list subscription allowed in a for loop? [duplicate]

    1 answer



I have the following code:



a = [0,1,2,3]

for a[-1] in a:
print(a[-1])


The output is:



0
1
2
2


I'm confused about why a list index can be used as an indexing variable in a for loop.










share|improve this question









New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











marked as duplicate by cs95 python
Users with the  python badge can single-handedly close python questions as duplicates and reopen them as needed.

StackExchange.ready(function()
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();

);
);
);
Apr 13 at 0:41


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.













  • 28





    Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

    – gameon67
    Apr 12 at 3:55






  • 13





    I don't know why you would ever want to do this, but now I know you can

    – Nathan
    Apr 12 at 3:57











  • over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

    – Arun Augustine
    Apr 12 at 4:01







  • 41





    This would be a great question for an awful coding interview

    – Nathan
    Apr 12 at 4:04






  • 2





    Btw OP, nice first question!

    – Christian Dean
    Apr 12 at 23:21

















76
















This question already has an answer here:



  • Why are arbitrary target expressions allowed in for-loops?

    4 answers



  • Are for-loop name list expressions legal?

    2 answers



  • Why is using a list subscription allowed in a for loop? [duplicate]

    1 answer



I have the following code:



a = [0,1,2,3]

for a[-1] in a:
print(a[-1])


The output is:



0
1
2
2


I'm confused about why a list index can be used as an indexing variable in a for loop.










share|improve this question









New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











marked as duplicate by cs95 python
Users with the  python badge can single-handedly close python questions as duplicates and reopen them as needed.

StackExchange.ready(function()
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();

);
);
);
Apr 13 at 0:41


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.













  • 28





    Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

    – gameon67
    Apr 12 at 3:55






  • 13





    I don't know why you would ever want to do this, but now I know you can

    – Nathan
    Apr 12 at 3:57











  • over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

    – Arun Augustine
    Apr 12 at 4:01







  • 41





    This would be a great question for an awful coding interview

    – Nathan
    Apr 12 at 4:04






  • 2





    Btw OP, nice first question!

    – Christian Dean
    Apr 12 at 23:21













76












76








76


16







This question already has an answer here:



  • Why are arbitrary target expressions allowed in for-loops?

    4 answers



  • Are for-loop name list expressions legal?

    2 answers



  • Why is using a list subscription allowed in a for loop? [duplicate]

    1 answer



I have the following code:



a = [0,1,2,3]

for a[-1] in a:
print(a[-1])


The output is:



0
1
2
2


I'm confused about why a list index can be used as an indexing variable in a for loop.










share|improve this question









New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.













This question already has an answer here:



  • Why are arbitrary target expressions allowed in for-loops?

    4 answers



  • Are for-loop name list expressions legal?

    2 answers



  • Why is using a list subscription allowed in a for loop? [duplicate]

    1 answer



I have the following code:



a = [0,1,2,3]

for a[-1] in a:
print(a[-1])


The output is:



0
1
2
2


I'm confused about why a list index can be used as an indexing variable in a for loop.





This question already has an answer here:



  • Why are arbitrary target expressions allowed in for-loops?

    4 answers



  • Are for-loop name list expressions legal?

    2 answers



  • Why is using a list subscription allowed in a for loop? [duplicate]

    1 answer







python for-loop indexing






share|improve this question









New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Apr 12 at 11:01









Peter Mortensen

13.9k1987114




13.9k1987114






New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Apr 12 at 3:45









Kundan VermaKundan Verma

21734




21734




New contributor




Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Kundan Verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




marked as duplicate by cs95 python
Users with the  python badge can single-handedly close python questions as duplicates and reopen them as needed.

StackExchange.ready(function()
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();

);
);
);
Apr 13 at 0:41


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.









marked as duplicate by cs95 python
Users with the  python badge can single-handedly close python questions as duplicates and reopen them as needed.

StackExchange.ready(function()
if (StackExchange.options.isMobile) return;

$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');

$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();

);
);
);
Apr 13 at 0:41


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.









  • 28





    Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

    – gameon67
    Apr 12 at 3:55






  • 13





    I don't know why you would ever want to do this, but now I know you can

    – Nathan
    Apr 12 at 3:57











  • over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

    – Arun Augustine
    Apr 12 at 4:01







  • 41





    This would be a great question for an awful coding interview

    – Nathan
    Apr 12 at 4:04






  • 2





    Btw OP, nice first question!

    – Christian Dean
    Apr 12 at 23:21












  • 28





    Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

    – gameon67
    Apr 12 at 3:55






  • 13





    I don't know why you would ever want to do this, but now I know you can

    – Nathan
    Apr 12 at 3:57











  • over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

    – Arun Augustine
    Apr 12 at 4:01







  • 41





    This would be a great question for an awful coding interview

    – Nathan
    Apr 12 at 4:04






  • 2





    Btw OP, nice first question!

    – Christian Dean
    Apr 12 at 23:21







28




28





Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

– gameon67
Apr 12 at 3:55





Somehow this question looks like a bad and newbie question, but I don't get the logic either lol

– gameon67
Apr 12 at 3:55




13




13





I don't know why you would ever want to do this, but now I know you can

– Nathan
Apr 12 at 3:57





I don't know why you would ever want to do this, but now I know you can

– Nathan
Apr 12 at 3:57













over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

– Arun Augustine
Apr 12 at 4:01






over the iteration only the last time a[-1] gets its value, all other times python treats as iteration variable.

– Arun Augustine
Apr 12 at 4:01





41




41





This would be a great question for an awful coding interview

– Nathan
Apr 12 at 4:04





This would be a great question for an awful coding interview

– Nathan
Apr 12 at 4:04




2




2





Btw OP, nice first question!

– Christian Dean
Apr 12 at 23:21





Btw OP, nice first question!

– Christian Dean
Apr 12 at 23:21












6 Answers
6






active

oldest

votes


















79














List indexes such as a[-1] in the expression for a[-1] in a are valid as specified by the for_stmt (and specifically the target_list) grammar token, where slicing is a valid target for assignment.



"Huh? Assignment? What has that got to do with my output?"



Indeed, it has everything to do with the output and result. Let's dive into the documentation for a for-in loop:




for_stmt ::= "for" target_list "in" expression_list ":" suite


The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed.




(emphasis added)
N.B. the suite refers to the statement(s) under the for-block, print(a[-1]) in our particular case.





Let's have a little fun and extend the print statement:



a = [0, 1, 2, 3]
for a[-1] in a:
print(a, a[-1])


This gives the following output:



[0, 1, 2, 0] 0 # a[-1] assigned 0
[0, 1, 2, 1] 1 # a[-1] assigned 1
[0, 1, 2, 2] 2 # a[-1] assigned 2
[0, 1, 2, 2] 2 # a[-1] assigned 2 (itself)


(comments added)



Here, a[-1] changes on each iteration and we see this change propagated to a. Again, this is possible due to slicing being a valid target.







A good argument made by Ev. Kounis regards the first sentence of the quoted doc above: "The expression list is evaluated once". Does this not imply that the expression list is static and immutable, constant at [0, 1, 2, 3]? Shouldn't a[-1] thus be assigned 3 at the final iteration?



Well, Konrad Rudolph asserts that:




No, [the expression list is] evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.




(emphasis added)



The following code demonstrates how an iterable it lazily yields elements of a list x.



x = [1, 2, 3, 4]
it = iter(x)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
x[-1] = 0
print(next(it)) # 0


(code inspired by Kounis')



If evaluation was eager, we could expect x[-1] = 0 to have zero effect on it and expect 4 to be printed. This is clearly not the case and goes to show that by the same principle, our for-loop lazily yields numbers from a following assignments to a[-1] on each iteration.






share|improve this answer




















  • 11





    Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

    – Christian Dean
    Apr 12 at 4:21






  • 4





    This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

    – Konrad Rudolph
    Apr 12 at 9:58






  • 1





    doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

    – Ev. Kounis
    Apr 12 at 11:04







  • 3





    @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

    – Konrad Rudolph
    Apr 12 at 11:14






  • 2





    @KonradRudolph I see..

    – Ev. Kounis
    Apr 12 at 11:23


















20














(This is more of a long comment than an answer - there are a couple of good ones already, especially @TrebledJ's. But I had to think of it explicitly in terms of overwriting variables that already have values before it clicked for me.)



If you had



x = 0
l = [1, 2, 3]
for x in l:
print(x)


you wouldn't be surprised that x is overridden each time through the loop. Even though x existed before, its value isn't used (i.e. for 0 in l:, which would throw an error). Rather, we assign the values from l to x.



When we do



a = [0, 1, 2, 3]

for a[-1] in a:
print(a[-1])


even though a[-1] already exists and has a value, we don't put that value in but rather assign to a[-1] each time through the loop.






share|improve this answer

























  • Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

    – Amir A. Shabani
    Apr 12 at 4:17


















6














The left expression of a for loop statement gets assigned with each item in the iterable on the right in each iteration, so



for n in a:
print(n)


is just a fancy way of doing:



for i in range(len(a)):
n = a[i]
print(n)


Likewise,



for a[-1] in a:
print(a[-1])


is just a fancy way of doing:



for i in range(len(a)):
a[-1] = a[i]
print(a[-1])


where in each iteration, the last item of a gets assigned with the next item in a, so when the iteration finally comes to the last item, its value got last assigned with the second-last item, 2.






share|improve this answer






























    6














    It is an interesting question, and you can understand it by that:



    for v in a:
    a[-1] = v
    print(a[-1])

    print(a)


    actually a becomes: [0, 1, 2, 2] after loop



    Output:



    0
    1
    2
    2
    [0, 1, 2, 2]


    I hope that helps you, and comment if you have further questions. : )






    share|improve this answer
































      4














      The answer by TrebledJ explains the technical reason of why this is possible.



      Why would you want to do this though?



      Suppose I have an algorithm that operates on an array:



      x = np.arange(5)


      And I want to test the result of the algorithm using different values of the first index. I can simply skip the first value, reconstructing an array every time:



      for i in range(5):
      print(np.r_[i, x[1:]].sum())


      (np.r_)



      This will create a new array on every iteration, which is not ideal, in particular if the array is large. To reuse the same memory on every iteration, I can rewrite it as:



      for i in range(5):
      x[0] = i
      print(x.sum())


      Which is probably clearer than the first version too.



      But that is exactly identical to the more compact way to write this:



      for x[0] in range(5):
      print(x.sum())


      all of the above will result in:



      10
      11
      12
      13
      14


      Now this is a trivial "algorithm", but there will be more complicated purposes where one might want to test changing a single (or multiple, but that complicating things due to assignment unpacking) value in an array to a number of values, preferably without copying the entire array. In this case, you may want to use an indexed value in a loop, but be prepared to confuse anyone maintaining your code (including yourself). For this reason, the second version explicitly assigning x[0] = i is probably preferable, but if you prefer the more compact for x[0] in range(5) style, this should be a valid use case.






      share|improve this answer

























      • What is np.r in the second code block?

        – Nathan
        Apr 13 at 2:41











      • @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

        – gerrit
        Apr 14 at 8:35











      • Ah, this should be np.r_; that's why I couldn't find it in my numpy.

        – Nathan
        Apr 14 at 18:53











      • @Nathan Oops! Corrected.

        – gerrit
        Apr 14 at 21:09


















      2














      a[-1] refers to the last element of a, in this case a[3]. The for loop is a bit unusual in that it is using this element as the loop variable.
      It's not evaluating that element upon loop entry, but rather it is assigning to it on each iteration through the loop.



      So first a[-1] gets set to 0, then 1, then 2. Finally, on the last iteration, the for loop retrieves a[3] which at that point is 2, so the list ends up as [0, 1, 2, 2].



      A more typical for loop uses a simple local variable name as the loop variable, e.g. for x .... In that case, x is set to the next value upon each iteration. This case is no different, except that a[-1] is set to the next value upon each iteration. You don't see this very often, but it's consistent.






      share|improve this answer

























      • How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

        – Amir A. Shabani
        Apr 12 at 3:53






      • 1





        Agree, I don't really understand by reading this answer

        – gameon67
        Apr 12 at 3:53











      • I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

        – Nathan
        Apr 12 at 3:56











      • I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

        – Tom Karzes
        Apr 12 at 4:05






      • 1





        "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

        – Christian Dean
        Apr 12 at 4:29


















      6 Answers
      6






      active

      oldest

      votes








      6 Answers
      6






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      79














      List indexes such as a[-1] in the expression for a[-1] in a are valid as specified by the for_stmt (and specifically the target_list) grammar token, where slicing is a valid target for assignment.



      "Huh? Assignment? What has that got to do with my output?"



      Indeed, it has everything to do with the output and result. Let's dive into the documentation for a for-in loop:




      for_stmt ::= "for" target_list "in" expression_list ":" suite


      The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed.




      (emphasis added)
      N.B. the suite refers to the statement(s) under the for-block, print(a[-1]) in our particular case.





      Let's have a little fun and extend the print statement:



      a = [0, 1, 2, 3]
      for a[-1] in a:
      print(a, a[-1])


      This gives the following output:



      [0, 1, 2, 0] 0 # a[-1] assigned 0
      [0, 1, 2, 1] 1 # a[-1] assigned 1
      [0, 1, 2, 2] 2 # a[-1] assigned 2
      [0, 1, 2, 2] 2 # a[-1] assigned 2 (itself)


      (comments added)



      Here, a[-1] changes on each iteration and we see this change propagated to a. Again, this is possible due to slicing being a valid target.







      A good argument made by Ev. Kounis regards the first sentence of the quoted doc above: "The expression list is evaluated once". Does this not imply that the expression list is static and immutable, constant at [0, 1, 2, 3]? Shouldn't a[-1] thus be assigned 3 at the final iteration?



      Well, Konrad Rudolph asserts that:




      No, [the expression list is] evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.




      (emphasis added)



      The following code demonstrates how an iterable it lazily yields elements of a list x.



      x = [1, 2, 3, 4]
      it = iter(x)
      print(next(it)) # 1
      print(next(it)) # 2
      print(next(it)) # 3
      x[-1] = 0
      print(next(it)) # 0


      (code inspired by Kounis')



      If evaluation was eager, we could expect x[-1] = 0 to have zero effect on it and expect 4 to be printed. This is clearly not the case and goes to show that by the same principle, our for-loop lazily yields numbers from a following assignments to a[-1] on each iteration.






      share|improve this answer




















      • 11





        Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

        – Christian Dean
        Apr 12 at 4:21






      • 4





        This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

        – Konrad Rudolph
        Apr 12 at 9:58






      • 1





        doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

        – Ev. Kounis
        Apr 12 at 11:04







      • 3





        @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

        – Konrad Rudolph
        Apr 12 at 11:14






      • 2





        @KonradRudolph I see..

        – Ev. Kounis
        Apr 12 at 11:23















      79














      List indexes such as a[-1] in the expression for a[-1] in a are valid as specified by the for_stmt (and specifically the target_list) grammar token, where slicing is a valid target for assignment.



      "Huh? Assignment? What has that got to do with my output?"



      Indeed, it has everything to do with the output and result. Let's dive into the documentation for a for-in loop:




      for_stmt ::= "for" target_list "in" expression_list ":" suite


      The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed.




      (emphasis added)
      N.B. the suite refers to the statement(s) under the for-block, print(a[-1]) in our particular case.





      Let's have a little fun and extend the print statement:



      a = [0, 1, 2, 3]
      for a[-1] in a:
      print(a, a[-1])


      This gives the following output:



      [0, 1, 2, 0] 0 # a[-1] assigned 0
      [0, 1, 2, 1] 1 # a[-1] assigned 1
      [0, 1, 2, 2] 2 # a[-1] assigned 2
      [0, 1, 2, 2] 2 # a[-1] assigned 2 (itself)


      (comments added)



      Here, a[-1] changes on each iteration and we see this change propagated to a. Again, this is possible due to slicing being a valid target.







      A good argument made by Ev. Kounis regards the first sentence of the quoted doc above: "The expression list is evaluated once". Does this not imply that the expression list is static and immutable, constant at [0, 1, 2, 3]? Shouldn't a[-1] thus be assigned 3 at the final iteration?



      Well, Konrad Rudolph asserts that:




      No, [the expression list is] evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.




      (emphasis added)



      The following code demonstrates how an iterable it lazily yields elements of a list x.



      x = [1, 2, 3, 4]
      it = iter(x)
      print(next(it)) # 1
      print(next(it)) # 2
      print(next(it)) # 3
      x[-1] = 0
      print(next(it)) # 0


      (code inspired by Kounis')



      If evaluation was eager, we could expect x[-1] = 0 to have zero effect on it and expect 4 to be printed. This is clearly not the case and goes to show that by the same principle, our for-loop lazily yields numbers from a following assignments to a[-1] on each iteration.






      share|improve this answer




















      • 11





        Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

        – Christian Dean
        Apr 12 at 4:21






      • 4





        This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

        – Konrad Rudolph
        Apr 12 at 9:58






      • 1





        doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

        – Ev. Kounis
        Apr 12 at 11:04







      • 3





        @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

        – Konrad Rudolph
        Apr 12 at 11:14






      • 2





        @KonradRudolph I see..

        – Ev. Kounis
        Apr 12 at 11:23













      79












      79








      79







      List indexes such as a[-1] in the expression for a[-1] in a are valid as specified by the for_stmt (and specifically the target_list) grammar token, where slicing is a valid target for assignment.



      "Huh? Assignment? What has that got to do with my output?"



      Indeed, it has everything to do with the output and result. Let's dive into the documentation for a for-in loop:




      for_stmt ::= "for" target_list "in" expression_list ":" suite


      The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed.




      (emphasis added)
      N.B. the suite refers to the statement(s) under the for-block, print(a[-1]) in our particular case.





      Let's have a little fun and extend the print statement:



      a = [0, 1, 2, 3]
      for a[-1] in a:
      print(a, a[-1])


      This gives the following output:



      [0, 1, 2, 0] 0 # a[-1] assigned 0
      [0, 1, 2, 1] 1 # a[-1] assigned 1
      [0, 1, 2, 2] 2 # a[-1] assigned 2
      [0, 1, 2, 2] 2 # a[-1] assigned 2 (itself)


      (comments added)



      Here, a[-1] changes on each iteration and we see this change propagated to a. Again, this is possible due to slicing being a valid target.







      A good argument made by Ev. Kounis regards the first sentence of the quoted doc above: "The expression list is evaluated once". Does this not imply that the expression list is static and immutable, constant at [0, 1, 2, 3]? Shouldn't a[-1] thus be assigned 3 at the final iteration?



      Well, Konrad Rudolph asserts that:




      No, [the expression list is] evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.




      (emphasis added)



      The following code demonstrates how an iterable it lazily yields elements of a list x.



      x = [1, 2, 3, 4]
      it = iter(x)
      print(next(it)) # 1
      print(next(it)) # 2
      print(next(it)) # 3
      x[-1] = 0
      print(next(it)) # 0


      (code inspired by Kounis')



      If evaluation was eager, we could expect x[-1] = 0 to have zero effect on it and expect 4 to be printed. This is clearly not the case and goes to show that by the same principle, our for-loop lazily yields numbers from a following assignments to a[-1] on each iteration.






      share|improve this answer















      List indexes such as a[-1] in the expression for a[-1] in a are valid as specified by the for_stmt (and specifically the target_list) grammar token, where slicing is a valid target for assignment.



      "Huh? Assignment? What has that got to do with my output?"



      Indeed, it has everything to do with the output and result. Let's dive into the documentation for a for-in loop:




      for_stmt ::= "for" target_list "in" expression_list ":" suite


      The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed.




      (emphasis added)
      N.B. the suite refers to the statement(s) under the for-block, print(a[-1]) in our particular case.





      Let's have a little fun and extend the print statement:



      a = [0, 1, 2, 3]
      for a[-1] in a:
      print(a, a[-1])


      This gives the following output:



      [0, 1, 2, 0] 0 # a[-1] assigned 0
      [0, 1, 2, 1] 1 # a[-1] assigned 1
      [0, 1, 2, 2] 2 # a[-1] assigned 2
      [0, 1, 2, 2] 2 # a[-1] assigned 2 (itself)


      (comments added)



      Here, a[-1] changes on each iteration and we see this change propagated to a. Again, this is possible due to slicing being a valid target.







      A good argument made by Ev. Kounis regards the first sentence of the quoted doc above: "The expression list is evaluated once". Does this not imply that the expression list is static and immutable, constant at [0, 1, 2, 3]? Shouldn't a[-1] thus be assigned 3 at the final iteration?



      Well, Konrad Rudolph asserts that:




      No, [the expression list is] evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.




      (emphasis added)



      The following code demonstrates how an iterable it lazily yields elements of a list x.



      x = [1, 2, 3, 4]
      it = iter(x)
      print(next(it)) # 1
      print(next(it)) # 2
      print(next(it)) # 3
      x[-1] = 0
      print(next(it)) # 0


      (code inspired by Kounis')



      If evaluation was eager, we could expect x[-1] = 0 to have zero effect on it and expect 4 to be printed. This is clearly not the case and goes to show that by the same principle, our for-loop lazily yields numbers from a following assignments to a[-1] on each iteration.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Apr 12 at 16:05

























      answered Apr 12 at 4:05









      TrebledJTrebledJ

      3,93921431




      3,93921431







      • 11





        Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

        – Christian Dean
        Apr 12 at 4:21






      • 4





        This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

        – Konrad Rudolph
        Apr 12 at 9:58






      • 1





        doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

        – Ev. Kounis
        Apr 12 at 11:04







      • 3





        @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

        – Konrad Rudolph
        Apr 12 at 11:14






      • 2





        @KonradRudolph I see..

        – Ev. Kounis
        Apr 12 at 11:23












      • 11





        Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

        – Christian Dean
        Apr 12 at 4:21






      • 4





        This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

        – Konrad Rudolph
        Apr 12 at 9:58






      • 1





        doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

        – Ev. Kounis
        Apr 12 at 11:04







      • 3





        @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

        – Konrad Rudolph
        Apr 12 at 11:14






      • 2





        @KonradRudolph I see..

        – Ev. Kounis
        Apr 12 at 11:23







      11




      11





      Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

      – Christian Dean
      Apr 12 at 4:21





      Essentially, the important thing to note here is that Python considers a[-1] to be a valid form of the left-hand side of an assignment statement (e.g. a[-1] = 1 is valid grammar). Thus a[-1] is a valid "variable" name, because as the documentation stated, it evaluates the binding variable(s) in a for loop declaration as it would the left-hand side of an assignment.

      – Christian Dean
      Apr 12 at 4:21




      4




      4





      This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

      – Konrad Rudolph
      Apr 12 at 9:58





      This answer is missing an important point, namely how the grammar defines target_list. For reasons that are utterly obscure to me, the grammar explicitly (rather than “accidentally”) allows the target list to contain slicing expressions (the syntax for the for loop simply recycles normal assignment targets, which seems odd).

      – Konrad Rudolph
      Apr 12 at 9:58




      1




      1





      doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

      – Ev. Kounis
      Apr 12 at 11:04






      doesn't the fact that a[-1] on the last iteration is 2 contradict the documentation in that "the expression list is evaluated once"?

      – Ev. Kounis
      Apr 12 at 11:04





      3




      3





      @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

      – Konrad Rudolph
      Apr 12 at 11:14





      @Ev.Kounis No, it’s evaluated once to create an iterable object. But that iterable object still iterates over the original data, not a copy of it.

      – Konrad Rudolph
      Apr 12 at 11:14




      2




      2





      @KonradRudolph I see..

      – Ev. Kounis
      Apr 12 at 11:23





      @KonradRudolph I see..

      – Ev. Kounis
      Apr 12 at 11:23













      20














      (This is more of a long comment than an answer - there are a couple of good ones already, especially @TrebledJ's. But I had to think of it explicitly in terms of overwriting variables that already have values before it clicked for me.)



      If you had



      x = 0
      l = [1, 2, 3]
      for x in l:
      print(x)


      you wouldn't be surprised that x is overridden each time through the loop. Even though x existed before, its value isn't used (i.e. for 0 in l:, which would throw an error). Rather, we assign the values from l to x.



      When we do



      a = [0, 1, 2, 3]

      for a[-1] in a:
      print(a[-1])


      even though a[-1] already exists and has a value, we don't put that value in but rather assign to a[-1] each time through the loop.






      share|improve this answer

























      • Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

        – Amir A. Shabani
        Apr 12 at 4:17















      20














      (This is more of a long comment than an answer - there are a couple of good ones already, especially @TrebledJ's. But I had to think of it explicitly in terms of overwriting variables that already have values before it clicked for me.)



      If you had



      x = 0
      l = [1, 2, 3]
      for x in l:
      print(x)


      you wouldn't be surprised that x is overridden each time through the loop. Even though x existed before, its value isn't used (i.e. for 0 in l:, which would throw an error). Rather, we assign the values from l to x.



      When we do



      a = [0, 1, 2, 3]

      for a[-1] in a:
      print(a[-1])


      even though a[-1] already exists and has a value, we don't put that value in but rather assign to a[-1] each time through the loop.






      share|improve this answer

























      • Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

        – Amir A. Shabani
        Apr 12 at 4:17













      20












      20








      20







      (This is more of a long comment than an answer - there are a couple of good ones already, especially @TrebledJ's. But I had to think of it explicitly in terms of overwriting variables that already have values before it clicked for me.)



      If you had



      x = 0
      l = [1, 2, 3]
      for x in l:
      print(x)


      you wouldn't be surprised that x is overridden each time through the loop. Even though x existed before, its value isn't used (i.e. for 0 in l:, which would throw an error). Rather, we assign the values from l to x.



      When we do



      a = [0, 1, 2, 3]

      for a[-1] in a:
      print(a[-1])


      even though a[-1] already exists and has a value, we don't put that value in but rather assign to a[-1] each time through the loop.






      share|improve this answer















      (This is more of a long comment than an answer - there are a couple of good ones already, especially @TrebledJ's. But I had to think of it explicitly in terms of overwriting variables that already have values before it clicked for me.)



      If you had



      x = 0
      l = [1, 2, 3]
      for x in l:
      print(x)


      you wouldn't be surprised that x is overridden each time through the loop. Even though x existed before, its value isn't used (i.e. for 0 in l:, which would throw an error). Rather, we assign the values from l to x.



      When we do



      a = [0, 1, 2, 3]

      for a[-1] in a:
      print(a[-1])


      even though a[-1] already exists and has a value, we don't put that value in but rather assign to a[-1] each time through the loop.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Apr 12 at 11:07









      Peter Mortensen

      13.9k1987114




      13.9k1987114










      answered Apr 12 at 4:14









      NathanNathan

      2,27511329




      2,27511329












      • Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

        – Amir A. Shabani
        Apr 12 at 4:17

















      • Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

        – Amir A. Shabani
        Apr 12 at 4:17
















      Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

      – Amir A. Shabani
      Apr 12 at 4:17





      Somehow I thought the variable used in for loop is immutable. +1 for pointing it out.

      – Amir A. Shabani
      Apr 12 at 4:17











      6














      The left expression of a for loop statement gets assigned with each item in the iterable on the right in each iteration, so



      for n in a:
      print(n)


      is just a fancy way of doing:



      for i in range(len(a)):
      n = a[i]
      print(n)


      Likewise,



      for a[-1] in a:
      print(a[-1])


      is just a fancy way of doing:



      for i in range(len(a)):
      a[-1] = a[i]
      print(a[-1])


      where in each iteration, the last item of a gets assigned with the next item in a, so when the iteration finally comes to the last item, its value got last assigned with the second-last item, 2.






      share|improve this answer



























        6














        The left expression of a for loop statement gets assigned with each item in the iterable on the right in each iteration, so



        for n in a:
        print(n)


        is just a fancy way of doing:



        for i in range(len(a)):
        n = a[i]
        print(n)


        Likewise,



        for a[-1] in a:
        print(a[-1])


        is just a fancy way of doing:



        for i in range(len(a)):
        a[-1] = a[i]
        print(a[-1])


        where in each iteration, the last item of a gets assigned with the next item in a, so when the iteration finally comes to the last item, its value got last assigned with the second-last item, 2.






        share|improve this answer

























          6












          6








          6







          The left expression of a for loop statement gets assigned with each item in the iterable on the right in each iteration, so



          for n in a:
          print(n)


          is just a fancy way of doing:



          for i in range(len(a)):
          n = a[i]
          print(n)


          Likewise,



          for a[-1] in a:
          print(a[-1])


          is just a fancy way of doing:



          for i in range(len(a)):
          a[-1] = a[i]
          print(a[-1])


          where in each iteration, the last item of a gets assigned with the next item in a, so when the iteration finally comes to the last item, its value got last assigned with the second-last item, 2.






          share|improve this answer













          The left expression of a for loop statement gets assigned with each item in the iterable on the right in each iteration, so



          for n in a:
          print(n)


          is just a fancy way of doing:



          for i in range(len(a)):
          n = a[i]
          print(n)


          Likewise,



          for a[-1] in a:
          print(a[-1])


          is just a fancy way of doing:



          for i in range(len(a)):
          a[-1] = a[i]
          print(a[-1])


          where in each iteration, the last item of a gets assigned with the next item in a, so when the iteration finally comes to the last item, its value got last assigned with the second-last item, 2.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Apr 12 at 4:08









          blhsingblhsing

          44.5k51745




          44.5k51745





















              6














              It is an interesting question, and you can understand it by that:



              for v in a:
              a[-1] = v
              print(a[-1])

              print(a)


              actually a becomes: [0, 1, 2, 2] after loop



              Output:



              0
              1
              2
              2
              [0, 1, 2, 2]


              I hope that helps you, and comment if you have further questions. : )






              share|improve this answer





























                6














                It is an interesting question, and you can understand it by that:



                for v in a:
                a[-1] = v
                print(a[-1])

                print(a)


                actually a becomes: [0, 1, 2, 2] after loop



                Output:



                0
                1
                2
                2
                [0, 1, 2, 2]


                I hope that helps you, and comment if you have further questions. : )






                share|improve this answer



























                  6












                  6








                  6







                  It is an interesting question, and you can understand it by that:



                  for v in a:
                  a[-1] = v
                  print(a[-1])

                  print(a)


                  actually a becomes: [0, 1, 2, 2] after loop



                  Output:



                  0
                  1
                  2
                  2
                  [0, 1, 2, 2]


                  I hope that helps you, and comment if you have further questions. : )






                  share|improve this answer















                  It is an interesting question, and you can understand it by that:



                  for v in a:
                  a[-1] = v
                  print(a[-1])

                  print(a)


                  actually a becomes: [0, 1, 2, 2] after loop



                  Output:



                  0
                  1
                  2
                  2
                  [0, 1, 2, 2]


                  I hope that helps you, and comment if you have further questions. : )







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 12 at 11:10

























                  answered Apr 12 at 4:03









                  recnacrecnac

                  2,1172631




                  2,1172631





















                      4














                      The answer by TrebledJ explains the technical reason of why this is possible.



                      Why would you want to do this though?



                      Suppose I have an algorithm that operates on an array:



                      x = np.arange(5)


                      And I want to test the result of the algorithm using different values of the first index. I can simply skip the first value, reconstructing an array every time:



                      for i in range(5):
                      print(np.r_[i, x[1:]].sum())


                      (np.r_)



                      This will create a new array on every iteration, which is not ideal, in particular if the array is large. To reuse the same memory on every iteration, I can rewrite it as:



                      for i in range(5):
                      x[0] = i
                      print(x.sum())


                      Which is probably clearer than the first version too.



                      But that is exactly identical to the more compact way to write this:



                      for x[0] in range(5):
                      print(x.sum())


                      all of the above will result in:



                      10
                      11
                      12
                      13
                      14


                      Now this is a trivial "algorithm", but there will be more complicated purposes where one might want to test changing a single (or multiple, but that complicating things due to assignment unpacking) value in an array to a number of values, preferably without copying the entire array. In this case, you may want to use an indexed value in a loop, but be prepared to confuse anyone maintaining your code (including yourself). For this reason, the second version explicitly assigning x[0] = i is probably preferable, but if you prefer the more compact for x[0] in range(5) style, this should be a valid use case.






                      share|improve this answer

























                      • What is np.r in the second code block?

                        – Nathan
                        Apr 13 at 2:41











                      • @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                        – gerrit
                        Apr 14 at 8:35











                      • Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                        – Nathan
                        Apr 14 at 18:53











                      • @Nathan Oops! Corrected.

                        – gerrit
                        Apr 14 at 21:09















                      4














                      The answer by TrebledJ explains the technical reason of why this is possible.



                      Why would you want to do this though?



                      Suppose I have an algorithm that operates on an array:



                      x = np.arange(5)


                      And I want to test the result of the algorithm using different values of the first index. I can simply skip the first value, reconstructing an array every time:



                      for i in range(5):
                      print(np.r_[i, x[1:]].sum())


                      (np.r_)



                      This will create a new array on every iteration, which is not ideal, in particular if the array is large. To reuse the same memory on every iteration, I can rewrite it as:



                      for i in range(5):
                      x[0] = i
                      print(x.sum())


                      Which is probably clearer than the first version too.



                      But that is exactly identical to the more compact way to write this:



                      for x[0] in range(5):
                      print(x.sum())


                      all of the above will result in:



                      10
                      11
                      12
                      13
                      14


                      Now this is a trivial "algorithm", but there will be more complicated purposes where one might want to test changing a single (or multiple, but that complicating things due to assignment unpacking) value in an array to a number of values, preferably without copying the entire array. In this case, you may want to use an indexed value in a loop, but be prepared to confuse anyone maintaining your code (including yourself). For this reason, the second version explicitly assigning x[0] = i is probably preferable, but if you prefer the more compact for x[0] in range(5) style, this should be a valid use case.






                      share|improve this answer

























                      • What is np.r in the second code block?

                        – Nathan
                        Apr 13 at 2:41











                      • @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                        – gerrit
                        Apr 14 at 8:35











                      • Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                        – Nathan
                        Apr 14 at 18:53











                      • @Nathan Oops! Corrected.

                        – gerrit
                        Apr 14 at 21:09













                      4












                      4








                      4







                      The answer by TrebledJ explains the technical reason of why this is possible.



                      Why would you want to do this though?



                      Suppose I have an algorithm that operates on an array:



                      x = np.arange(5)


                      And I want to test the result of the algorithm using different values of the first index. I can simply skip the first value, reconstructing an array every time:



                      for i in range(5):
                      print(np.r_[i, x[1:]].sum())


                      (np.r_)



                      This will create a new array on every iteration, which is not ideal, in particular if the array is large. To reuse the same memory on every iteration, I can rewrite it as:



                      for i in range(5):
                      x[0] = i
                      print(x.sum())


                      Which is probably clearer than the first version too.



                      But that is exactly identical to the more compact way to write this:



                      for x[0] in range(5):
                      print(x.sum())


                      all of the above will result in:



                      10
                      11
                      12
                      13
                      14


                      Now this is a trivial "algorithm", but there will be more complicated purposes where one might want to test changing a single (or multiple, but that complicating things due to assignment unpacking) value in an array to a number of values, preferably without copying the entire array. In this case, you may want to use an indexed value in a loop, but be prepared to confuse anyone maintaining your code (including yourself). For this reason, the second version explicitly assigning x[0] = i is probably preferable, but if you prefer the more compact for x[0] in range(5) style, this should be a valid use case.






                      share|improve this answer















                      The answer by TrebledJ explains the technical reason of why this is possible.



                      Why would you want to do this though?



                      Suppose I have an algorithm that operates on an array:



                      x = np.arange(5)


                      And I want to test the result of the algorithm using different values of the first index. I can simply skip the first value, reconstructing an array every time:



                      for i in range(5):
                      print(np.r_[i, x[1:]].sum())


                      (np.r_)



                      This will create a new array on every iteration, which is not ideal, in particular if the array is large. To reuse the same memory on every iteration, I can rewrite it as:



                      for i in range(5):
                      x[0] = i
                      print(x.sum())


                      Which is probably clearer than the first version too.



                      But that is exactly identical to the more compact way to write this:



                      for x[0] in range(5):
                      print(x.sum())


                      all of the above will result in:



                      10
                      11
                      12
                      13
                      14


                      Now this is a trivial "algorithm", but there will be more complicated purposes where one might want to test changing a single (or multiple, but that complicating things due to assignment unpacking) value in an array to a number of values, preferably without copying the entire array. In this case, you may want to use an indexed value in a loop, but be prepared to confuse anyone maintaining your code (including yourself). For this reason, the second version explicitly assigning x[0] = i is probably preferable, but if you prefer the more compact for x[0] in range(5) style, this should be a valid use case.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Apr 14 at 21:09

























                      answered Apr 12 at 11:12









                      gerritgerrit

                      7,80654894




                      7,80654894












                      • What is np.r in the second code block?

                        – Nathan
                        Apr 13 at 2:41











                      • @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                        – gerrit
                        Apr 14 at 8:35











                      • Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                        – Nathan
                        Apr 14 at 18:53











                      • @Nathan Oops! Corrected.

                        – gerrit
                        Apr 14 at 21:09

















                      • What is np.r in the second code block?

                        – Nathan
                        Apr 13 at 2:41











                      • @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                        – gerrit
                        Apr 14 at 8:35











                      • Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                        – Nathan
                        Apr 14 at 18:53











                      • @Nathan Oops! Corrected.

                        – gerrit
                        Apr 14 at 21:09
















                      What is np.r in the second code block?

                      – Nathan
                      Apr 13 at 2:41





                      What is np.r in the second code block?

                      – Nathan
                      Apr 13 at 2:41













                      @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                      – gerrit
                      Apr 14 at 8:35





                      @Nathan docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html

                      – gerrit
                      Apr 14 at 8:35













                      Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                      – Nathan
                      Apr 14 at 18:53





                      Ah, this should be np.r_; that's why I couldn't find it in my numpy.

                      – Nathan
                      Apr 14 at 18:53













                      @Nathan Oops! Corrected.

                      – gerrit
                      Apr 14 at 21:09





                      @Nathan Oops! Corrected.

                      – gerrit
                      Apr 14 at 21:09











                      2














                      a[-1] refers to the last element of a, in this case a[3]. The for loop is a bit unusual in that it is using this element as the loop variable.
                      It's not evaluating that element upon loop entry, but rather it is assigning to it on each iteration through the loop.



                      So first a[-1] gets set to 0, then 1, then 2. Finally, on the last iteration, the for loop retrieves a[3] which at that point is 2, so the list ends up as [0, 1, 2, 2].



                      A more typical for loop uses a simple local variable name as the loop variable, e.g. for x .... In that case, x is set to the next value upon each iteration. This case is no different, except that a[-1] is set to the next value upon each iteration. You don't see this very often, but it's consistent.






                      share|improve this answer

























                      • How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                        – Amir A. Shabani
                        Apr 12 at 3:53






                      • 1





                        Agree, I don't really understand by reading this answer

                        – gameon67
                        Apr 12 at 3:53











                      • I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                        – Nathan
                        Apr 12 at 3:56











                      • I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                        – Tom Karzes
                        Apr 12 at 4:05






                      • 1





                        "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                        – Christian Dean
                        Apr 12 at 4:29
















                      2














                      a[-1] refers to the last element of a, in this case a[3]. The for loop is a bit unusual in that it is using this element as the loop variable.
                      It's not evaluating that element upon loop entry, but rather it is assigning to it on each iteration through the loop.



                      So first a[-1] gets set to 0, then 1, then 2. Finally, on the last iteration, the for loop retrieves a[3] which at that point is 2, so the list ends up as [0, 1, 2, 2].



                      A more typical for loop uses a simple local variable name as the loop variable, e.g. for x .... In that case, x is set to the next value upon each iteration. This case is no different, except that a[-1] is set to the next value upon each iteration. You don't see this very often, but it's consistent.






                      share|improve this answer

























                      • How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                        – Amir A. Shabani
                        Apr 12 at 3:53






                      • 1





                        Agree, I don't really understand by reading this answer

                        – gameon67
                        Apr 12 at 3:53











                      • I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                        – Nathan
                        Apr 12 at 3:56











                      • I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                        – Tom Karzes
                        Apr 12 at 4:05






                      • 1





                        "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                        – Christian Dean
                        Apr 12 at 4:29














                      2












                      2








                      2







                      a[-1] refers to the last element of a, in this case a[3]. The for loop is a bit unusual in that it is using this element as the loop variable.
                      It's not evaluating that element upon loop entry, but rather it is assigning to it on each iteration through the loop.



                      So first a[-1] gets set to 0, then 1, then 2. Finally, on the last iteration, the for loop retrieves a[3] which at that point is 2, so the list ends up as [0, 1, 2, 2].



                      A more typical for loop uses a simple local variable name as the loop variable, e.g. for x .... In that case, x is set to the next value upon each iteration. This case is no different, except that a[-1] is set to the next value upon each iteration. You don't see this very often, but it's consistent.






                      share|improve this answer















                      a[-1] refers to the last element of a, in this case a[3]. The for loop is a bit unusual in that it is using this element as the loop variable.
                      It's not evaluating that element upon loop entry, but rather it is assigning to it on each iteration through the loop.



                      So first a[-1] gets set to 0, then 1, then 2. Finally, on the last iteration, the for loop retrieves a[3] which at that point is 2, so the list ends up as [0, 1, 2, 2].



                      A more typical for loop uses a simple local variable name as the loop variable, e.g. for x .... In that case, x is set to the next value upon each iteration. This case is no different, except that a[-1] is set to the next value upon each iteration. You don't see this very often, but it's consistent.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Apr 12 at 4:47

























                      answered Apr 12 at 3:51









                      Tom KarzesTom Karzes

                      11.3k1926




                      11.3k1926












                      • How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                        – Amir A. Shabani
                        Apr 12 at 3:53






                      • 1





                        Agree, I don't really understand by reading this answer

                        – gameon67
                        Apr 12 at 3:53











                      • I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                        – Nathan
                        Apr 12 at 3:56











                      • I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                        – Tom Karzes
                        Apr 12 at 4:05






                      • 1





                        "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                        – Christian Dean
                        Apr 12 at 4:29


















                      • How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                        – Amir A. Shabani
                        Apr 12 at 3:53






                      • 1





                        Agree, I don't really understand by reading this answer

                        – gameon67
                        Apr 12 at 3:53











                      • I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                        – Nathan
                        Apr 12 at 3:56











                      • I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                        – Tom Karzes
                        Apr 12 at 4:05






                      • 1





                        "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                        – Christian Dean
                        Apr 12 at 4:29

















                      How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                      – Amir A. Shabani
                      Apr 12 at 3:53





                      How does it actually gets set to 0, then 1, then 2 and finally 2? That's the confusing part!

                      – Amir A. Shabani
                      Apr 12 at 3:53




                      1




                      1





                      Agree, I don't really understand by reading this answer

                      – gameon67
                      Apr 12 at 3:53





                      Agree, I don't really understand by reading this answer

                      – gameon67
                      Apr 12 at 3:53













                      I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                      – Nathan
                      Apr 12 at 3:56





                      I expected it would be like saying for 3 in a: print(a[-1]) (because a[-1] was 3 at the start of the loop) and give an error, but clearly that's not the case. You're obviously correct about what's happening, but I'm surprised this evaluates this way.

                      – Nathan
                      Apr 12 at 3:56













                      I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                      – Tom Karzes
                      Apr 12 at 4:05





                      I've expanded the answer to explain more precisely how this works. Hopefully people will understand it this time.

                      – Tom Karzes
                      Apr 12 at 4:05




                      1




                      1





                      "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                      – Christian Dean
                      Apr 12 at 4:29






                      "The for loop is a bit unusual in that it is using this element as the loop variable." - This may be where the confusion is coming from. Python isn't using the element a[-1] evaluates to, rather, it's using the index a[-1] itself. If you rephrase that statement, your answer becomes much more clear.

                      – Christian Dean
                      Apr 12 at 4:29




                      Popular posts from this blog

                      Club Baloncesto Breogán Índice Historia | Pavillón | Nome | O Breogán na cultura popular | Xogadores | Adestradores | Presidentes | Palmarés | Historial | Líderes | Notas | Véxase tamén | Menú de navegacióncbbreogan.galCadroGuía oficial da ACB 2009-10, páxina 201Guía oficial ACB 1992, páxina 183. Editorial DB.É de 6.500 espectadores sentados axeitándose á última normativa"Estudiantes Junior, entre as mellores canteiras"o orixinalHemeroteca El Mundo Deportivo, 16 setembro de 1970, páxina 12Historia do BreogánAlfredo Pérez, o último canoneiroHistoria C.B. BreogánHemeroteca de El Mundo DeportivoJimmy Wright, norteamericano do Breogán deixará Lugo por ameazas de morteResultados de Breogán en 1986-87Resultados de Breogán en 1990-91Ficha de Velimir Perasović en acb.comResultados de Breogán en 1994-95Breogán arrasa al Barça. "El Mundo Deportivo", 27 de setembro de 1999, páxina 58CB Breogán - FC BarcelonaA FEB invita a participar nunha nova Liga EuropeaCharlie Bell na prensa estatalMáximos anotadores 2005Tempada 2005-06 : Tódolos Xogadores da Xornada""Non quero pensar nunha man negra, mais pregúntome que está a pasar""o orixinalRaúl López, orgulloso dos xogadores, presume da boa saúde económica do BreogánJulio González confirma que cesa como presidente del BreogánHomenaxe a Lisardo GómezA tempada do rexurdimento celesteEntrevista a Lisardo GómezEl COB dinamita el Pazo para forzar el quinto (69-73)Cafés Candelas, patrocinador del CB Breogán"Suso Lázare, novo presidente do Breogán"o orixinalCafés Candelas Breogán firma el mayor triunfo de la historiaEl Breogán realizará 17 homenajes por su cincuenta aniversario"O Breogán honra ao seu fundador e primeiro presidente"o orixinalMiguel Giao recibiu a homenaxe do PazoHomenaxe aos primeiros gladiadores celestesO home que nos amosa como ver o Breo co corazónTita Franco será homenaxeada polos #50anosdeBreoJulio Vila recibirá unha homenaxe in memoriam polos #50anosdeBreo"O Breogán homenaxeará aos seus aboados máis veteráns"Pechada ovación a «Capi» Sanmartín e Ricardo «Corazón de González»Homenaxe por décadas de informaciónPaco García volve ao Pazo con motivo do 50 aniversario"Resultados y clasificaciones""O Cafés Candelas Breogán, campión da Copa Princesa""O Cafés Candelas Breogán, equipo ACB"C.B. Breogán"Proxecto social"o orixinal"Centros asociados"o orixinalFicha en imdb.comMario Camus trata la recuperación del amor en 'La vieja música', su última película"Páxina web oficial""Club Baloncesto Breogán""C. B. Breogán S.A.D."eehttp://www.fegaba.com

                      Vilaño, A Laracha Índice Patrimonio | Lugares e parroquias | Véxase tamén | Menú de navegación43°14′52″N 8°36′03″O / 43.24775, -8.60070

                      Cegueira Índice Epidemioloxía | Deficiencia visual | Tipos de cegueira | Principais causas de cegueira | Tratamento | Técnicas de adaptación e axudas | Vida dos cegos | Primeiros auxilios | Crenzas respecto das persoas cegas | Crenzas das persoas cegas | O neno deficiente visual | Aspectos psicolóxicos da cegueira | Notas | Véxase tamén | Menú de navegación54.054.154.436928256blindnessDicionario da Real Academia GalegaPortal das Palabras"International Standards: Visual Standards — Aspects and Ranges of Vision Loss with Emphasis on Population Surveys.""Visual impairment and blindness""Presentan un plan para previr a cegueira"o orixinalACCDV Associació Catalana de Cecs i Disminuïts Visuals - PMFTrachoma"Effect of gene therapy on visual function in Leber's congenital amaurosis"1844137110.1056/NEJMoa0802268Cans guía - os mellores amigos dos cegosArquivadoEscola de cans guía para cegos en Mortágua, PortugalArquivado"Tecnología para ciegos y deficientes visuales. Recopilación de recursos gratuitos en la Red""Colorino""‘COL.diesis’, escuchar los sonidos del color""COL.diesis: Transforming Colour into Melody and Implementing the Result in a Colour Sensor Device"o orixinal"Sistema de desarrollo de sinestesia color-sonido para invidentes utilizando un protocolo de audio""Enseñanza táctil - geometría y color. Juegos didácticos para niños ciegos y videntes""Sistema Constanz"L'ocupació laboral dels cecs a l'Estat espanyol està pràcticament equiparada a la de les persones amb visió, entrevista amb Pedro ZuritaONCE (Organización Nacional de Cegos de España)Prevención da cegueiraDescrición de deficiencias visuais (Disc@pnet)Braillín, un boneco atractivo para calquera neno, con ou sen discapacidade, que permite familiarizarse co sistema de escritura e lectura brailleAxudas Técnicas36838ID00897494007150-90057129528256DOID:1432HP:0000618D001766C10.597.751.941.162C97109C0155020