Python append behaviour odd? [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Why does foo.append(bar) affect all elements in a list of lists?
(3 answers)
Closed 6 years ago.
I've encountered what I think is odd behaviour for the append() function, and I've managed to duplicate it in the following simplified code:
plugh1 = []
plugh2 = []
n = 0
while n <= 4:
plugh1.append(n)
plugh2.append(plugh1)
n = n+1
print plugh1
print plugh2
I would expect this code to result in:
plugh1 = [1, 2, 3, 4]
plugh2 = [[1], [1, 2], [1, 2, 3, ], [1, 2, 3, 4]]
but the actual result is:
plugh1 = [1, 2, 3, 4]
plugh2 = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
As the loop runs, each time all array elements are replaced with the value of plugh1.
There is a similar question on SO but the solution seems related to nesting functions and defining a variable outside of those calls. This is much simpler I think. What am I missing?

When you do
plugh2.append(plugh1)
you are actually appending a reference to the first list, not the list as it currently is. Therefore the next time you do
plugh1.append(n)
you are changing the contents inside plugh2, as well.
You could copy the list like so, so that it doesn't change afterwards.
plugh2.append(plugh1[:])

The reason this occurs is that you are not copying the list itself, but only the reference to the list. Try running:
print(pligh2[0] is pligh2[1])
#: True
Each element in the list "is" every other element because they are all the same objects.
If you want to copy this lists themselves, try:
plugh2.append(plugh1[:])
# or
plugh2.append(plugh1.copy())

This:
plugh2.append(plugh1)
Appends a reference to plugh1, not a copy. This means future updates are reflected in plugh2. If you need a copy, see here: https://docs.python.org/2/library/copy.html

Related

How do I move items from one list to another? [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 10 months ago.
I am trying to remove all the items from list2 into list1 like this:
l1 = [1, 2, 3]
l2 = [4, 5, 6]
for item in l2:
l1.append(item)
l2.remove(item)
the problem is:
#l1 now returns [1, 2, 3, 4, 6]
#l2 now returns [5]
I want it so that:
#l1 returns [1, 2, 3, 4, 5, 6]
#l2 returns []
Why does this happen? And what is the conventional way to achieve what I'm trying to do, in Python?
Your code doesn't work because you are removing items while iterating.
For your problem - moving all items from one list to another list - the best solution is to use built-in methods provided by lists (the latter since Python 3.3):
l1.extend(l2)
l2.clear()
you can replace l2.clear() with l2 = [] if there are no other references to l2

How does pop() function works in python? It doesn't work in a way that I expect [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 12 months ago.
I have these lines of codes in a class in python:
1 for i in range(len(self.rg_nodes_range)):
2 tmp_rg = self.rg_nodes_range
3 tmp_rg.pop(i)
The value for self.rg_nodes_range is:
self.rg_nodes_range = [20, 21]
I expect that at the start of every loop, tmp_rg gets the value of [20, 21], and then in line 3, drop the corresponding index (i) from tmp_rg. For example, I want tmp_rg to be [21] at the end of the first iteration (when i==0), and to be [20]
at the end of the second iteration (when i==1).
But it seems that it's not happening. I put some breakpoints and found out that in the first iteration, in line 3, tmp_rg and self.rg_nodes_range both change from [20, 21] to [21]. I double-checked it with these lines of code:
p = [1, 2, 3]
tp = p
tp.pop(0)
print(p)
print(tp)
and the output was (both p and tp changed):
[2, 3]
[2, 3]
Do you know what happens here? And how can I fix it to obtain my expected outputs?
Thank you.
It is not a pop() problem. The function is working as expected what you need to look for is deep vs shallow copy concept as in python when you assign a variable to other, it simply creates a shallow copy thus modifying original will modify the copy as well. However if you create a deep copy it will clone the objects allowing you to modify them separately.
So this:
p = [1, 2, 3]
tp = p
tp.pop(0)
print(p)
print(tp)
produces:
[2, 3]
[2, 3]
However this:
p = [1, 2, 3]
tp = p.copy()
tp.pop(0)
print(p)
print(tp)
produces
[1, 2, 3]
[2, 3]

Appending variable that is modified in a for loop doesn't work as expected [duplicate]

This question already has answers here:
List on python appending always the same value [duplicate]
(5 answers)
Closed 4 years ago.
I have this code:
lst = []
given = [1, 2, 3, 4, 5]
result = []
for item in given:
lst.append(item)
print(lst)
result.append(lst)
print(result)
My expected result is [[1], [1, 2], [1, 2, 3], ...], but displayed result is [[1, 2, 3, 4, 5], ...] with 12345 repeated 5 times. What is wrong?
lst printed is as expected, which is [1] for the first loop, [1, 2] for the second loop, and so on.
Python doesn't create copy of lst every time when you append it to result, it just inserts reference. As a result you get list with N references to same list.
To create a copy of lst you can use lst.copy(). Also list slice operator works same lst[:].
Shortened version of your code:
given = [1, 2, 3, 4, 5]
result = [given[0 : i + 1] for i in range(len(given))]
print(result)
Result:
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
The problem is that you are appending the list as such which is equivalent to appending the reference object to the original list. Therefore, whenever the original list is modified, the changes are reflected in the places where the reference is created, in this case in result. As you keep iterating via the for loop, all your references appended in result keep getting updated with the latest value of lst. The final result is that at the end of the for loop, you have appended 5 references to the original list lst and all of them store the latest value of lst being [1,2,3,4,5].
There are several ways to avoid this. What you need is to copy only the values. One of them is to use lst[:]. other way is to use lst.copy()
for item in given:
lst.append(item)
print(lst)
result.append(lst[:])
print (result)
# [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
List is a mutable data type, there is only one copy in memory for a list unless you explicitly copy it to another variable. So
result.append(lst)
just appends a reference of the real copy and all the refercences point to the same copy.
In conclusion, you should learn about mutable/immutable data types and reference count in python.
Append lst.copy() gives the right output.
lst = []
given = [1,2,3,4,5]
result = []
for item in given:
lst.append(item)
print(lst)
result.append(lst.copy())
print(result)

How to initialize a list and extend it with another list in one line? [duplicate]

This question already has answers here:
How do I concatenate two lists in Python?
(31 answers)
Closed 5 years ago.
This sounds like a super easy question, so I'm surprised that searching didn't yield any results: I want to initialize a list of constants and extend it with a list from another source.
This works:
remoteList = [2, 3, 4]
myList = [0,1]
myList.extend(remoteList)
Which means it gives the expected results:
myList
[0, 1, 2, 3, 4]
However, doing the list initialization in one line doesn't work, myList is left undefined:
remoteList = [2, 3, 4]
myList = [0,1].extend(remoteList)
Is there a way to initialize the list and extend it with another list (in a pythonic way) in one line? Why doesn't my one line example work, or at least produce some sort of list?
You can use unpacking inside the list literal
myList = [0, 1, *remoteList]
This is part of the unpacking generalizations made available in Python 3.5
Are not you just asking about the + list concatenation operation:
In [1]: remoteList = [2, 3, 4]
In [2]: myList = [0, 1] + remoteList
In [3]: myList
Out[3]: [0, 1, 2, 3, 4]
Works for both Python 2 and 3.
There are some slight differences between "extend" and "plus":
Concatenating two lists - difference between '+=' and extend()
a = [2,3,4]
b = [1,2] + a # will add the other list
print( b)
Output:
[1, 2, 2, 3, 4]

Python populating all the elements of a 2D list (or array) when I change only one [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python : how to append new elements in a list of list?
I came up with this very strange (for me) behaviour in Python.
I have an empty 2D list (or array if you prefer), and when I add an element to one of it's columns, all the other columns get the same value added.
Here is the code:
row = [1, 2, 3, 4]
yChannel = 4*[[]]
sectorPlace = 0
for sector in yChannel:
sector.append(row[sectorPlace])
sectorPlace += 1
print yChannel
And the output:
[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
yChannel contains 4 copies of the same list. Compare what you have with:
yChannel = [[], [], [], []]
The line
yChannel = 4*[[]]
creates a list with four times the same list object. Modifying this single list object will seemingly modify all for sublists, since they are actually all the same list object. You should use
yChannel = [[] for dummy in range(4)]
to create a list of four independent sublists.

Categories