简体   繁体   中英

Python Beginner Question: Can someone help me understand why the output is [1,1,1,1,2,3]?

my_list = [1,2,3]
for v in range (len(my_list)):
    my_list.insert(1,my_list[v])

print(my_list)

#outputs [1,1,1,1,2,3]

I am getting tripped up on why the value of V is set to 1 instead of iterating through the other number found in the list. I've tried reading up on W3 schools but still confused

This is because you insert the value 1 before the #1 position in the list, but because the list updates every iteration, the value in the #1 position is always 1. to see this clearly, you can print the list in every iteration

[1,1,2,3]
[1,1,1,2,3]
[1,1,1,1,2,3]

the only thing not updating is the range() that was set to the length of the original list (range(0,3)->v=0,v=1,v=2)

The reason isn't exactly that you're modifying the list you're iterating over-- it's because range produces an immutable sequence of a fixed length, created exactly once. Therefore, the number of iterations of the for loop is based on len(my_list) at the beginning, which is 3. The list.insert(i, x) method puts x in index i, and shoves the old elements at indices (i, i+1...) to the right.

Thus your code is equivalent to:

my_list = [1,2,3]
for v in range(3):
    my_list.insert(1, my_list[v])

And, if we put parentheses around the new element just inserted in each of the 3 iterations:

my_list = [1, 2, 3]

Insert (my_list[0] == 1) at position 1
my_list = [1, (1), 2, 3]

Insert (my_list[1] == 1) at position 1
my_list = [1, (1), 1, 2, 3]

Insert (my_list[2] == 1) at position 1
my_list = [1, (1), 1, 1, 2, 3]

While this isn't as dangerous as iterating over the list directly while modifying it, the best way to avoid unexpected behavior is to make a copy of the list beforehand, and index into a different list than the one you're modifying.

You can add a print statement in the loop as follows which will make it easier to understand.

my_list = [1,2,3]
for v in range (len(my_list)):
    my_list.insert(1,my_list[v])
    print(f"mylist: {my_list}")
    print(f"mylist[v]: {my_list[v]}")
    print(f"v: {v}")
    

print(my_list)

above code results:

mylist: [1, 1, 2, 3]
mylist[v]: 1
v: 0
mylist: [1, 1, 1, 2, 3]
mylist[v]: 1
v: 1
mylist: [1, 1, 1, 1, 2, 3]
mylist[v]: 1
v: 2
[1, 1, 1, 1, 2, 3]

The len(my_list) in the range constructor is evaluated once, at the top of the first iteration of the loop, where the length of my_list is 3. This results in the loop variable v being set to 0, 1, and 2 as the loop iterates.

Inside the loop, you insert into the list at the second position (ie just after the first element of the list) the value of the existing element v of the list. v changes on each iteration (0, 1, 2) as you expect. But, so does my_list , since you are inserting an element with each iteration. So you get the following transformation of my_list:

Start:  my_list = [ 1 2 3 ]
v = 0:  my_list[0] = 1 -> my_list = [ 1 *1* 2 3 ] (*X* indicates inserted element)
v = 1:  my_list[1] = 1 -> my_list = [ 1 *1* 1 2 3 ]
v = 2:  my_list[2] = 1 -> my_list = [ 1 *1* 1 1 2 3 ]

Essentially, as you prepend elements to the list, the indices of the existing elements are shifting to the right.

Found this website with an explantion on this: Iterate a list using range() and for loop. https://pynative.com/python-range-function/ "When you iterate the list only using a loop, you can access only items. When you iterate the list only using a loop, you can only access its items, but when you use range() along with the loop, you can access the index number of each item.

The advantage of using range() to iterate a list is that it allows us to access each item's index number. Using index numbers, we can access as well as modify list items if required."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM