Python array strange behavior? [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 6 years ago.
Can anyone explain why is this happening?
Case 1:
>>> a = [[0]] *3
>>> print a
[[0], [0], [0]]
>>> a[1].append(0)
>>> print a
[[0, 0], [0, 0], [0, 0]]
Case 2:
>>> a = [[0],[0],[0]]
>>> print a
[[0], [0], [0]]
>>> a[1].append(0)
>>> print a
[[0], [0, 0], [0]]
Why is this going on? I am expecting that the behavior of the array in case 1 to be as in case 2 but it is not for some reason.

In the first case, the three elements in a actually reference to the same list objects. You can check their id:
>>> id(a[0])
4524132472
>>> id(a[1])
4524132472
>>> id(a[2])
4524132472

In the first case, you are creating a list [0] and duplicate it 3 times. This is the same object repeated three times. You should use the star form only with immutable type
To avoid this issue when you have a mutable type, use list comprehension:
a = [[0] for _ in range(3)]

Related

Unexpected behaviour of python matrix (list of lists), assignment is changing whole column [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 4 months ago.
please help me with a question, cause Im getting mad.
I'm creating a 0-matrix, than tried to changed it's first element value to one, but it changes the whole column instead, and I don't get why:
def id_mtrx(n):
m = [[0]*n]*n
m[0][0]=1
return m
here is output:
[[1, 0], [1, 0]]
while I was expecting:
[[1, 0], [0, 0]]
It looks very simple, what can be wrong?
You are creating multiple references to the same list object instead of creating new list, try:
n = 2
m = [[0 for _ in range(0, n)] for _ in range (0, n)]
m[0][0] = 1
print(m)
output is:
[[1, 0], [0, 0]]

Appending the same list to another one [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 6 years ago.
I have to append the same list to another one more than one time, and then modify only one of them.
I tried
list_a = []
list_b = [0,0,0]
for x in range(3):
list_a.append(list_b)
but the problem is that if I try
list_a[0][0] = 1
it modifies list_a[1][0] and list_a[2][0] also.
How can I avoid that?
Better way to create a list like this if all you want is to create empty list with all 0s is:
my_list = [[0]*3 for _ in range(3)]
Let's verify the result whether it has the same issue or not:
>>> my_list
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> my_list[0][0] = 1
>>> my_list
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
# ^ ^ ^
# Yipee! value changed only once
For knowing the reason why your code is not working, check: Python list of lists, changes reflected across sublists unexpectedly
Use the following:
list_a = []
list_b = [0,0,0]
for x in range(3):
list_a.append(list_b[:])
You are appending list_b three times, so what you are modifying is the actual list_b object. What you want to do is to make a shallow copy, this be done like this
list_a.append(list(list_b))
or like this
list_a.append(list_b[:])

Different behaviour when operating on equivalent multidimensional lists [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
When I operate on two, I think equivalent multidimensional lists, I have different outcomes. The only difference between the lists is how they are created. I'm using Python 3.4.3
>>> b = [[1,2],[1,2]]
>>> b[0][0] += 1
>>> b
[[2, 2], [1, 2]]
>>> b = [[1,2]] * 2
>>> b
[[1, 2], [1, 2]]
>>> b[0][0] += 1
>>> b
[[2, 2], [2, 2]]
As you can see, both b's and the operations on them are the same, but the outcome is not. I'm guessing that it has something to do with the way they are created since that is the only difference, but I don't see how.
Its the same with Python 2.7.6
>>> b = [[1,2],[1,2]]
>>> b
[[1, 2], [1, 2]]
>>> c = [[1,2]] * 2
>>> c
[[1, 2], [1, 2]]
>>> c == b
True
>>> b[0][0] += 1
>>> b
[[2, 2], [1, 2]]
>>> c[0][0] += 1
>>> c
[[2, 2], [2, 2]]
>>> c == b
False
>>>
b = [[1,2],[1,2]]
print(id(b[0])) # 139948012160968
print(id(b[1])) # 139948011731400
b = [[1,2]]*2
print(id(b[0])) # 139948012161032
print(id(b[1])) # 139948012161032
`id() shows the object's ID or the memory location in Python.
When you do b = [[1,2]]*2 you are basically saying let's point to the same object twice and store it in b in a list.
When you do b = [[1,2],[1,2]] you are basically saying let me get two different objects and put them in a list and let b reference the list.
So for the latter example, of course you are going to get that output since they are the same object you are changing. You can think of it as me giving you the same address to a house and I have the same address I gave you. We end up at the same place and what ever changes we make to the house, we see it together.
Edited for comment:
Correct! They are changing how the memory is handled but the values are the same.
== tests if the values are the same. is tests if the objects are the same. so in our case:
#First case:
print(b[0] == b[1]) #true
print(b[0] is b[1]) #false
#second case:
print(b[0] == b[1]) #true
print(b[0] is b[1]) #true
Edited second time for second comment!~
import copy
x = [1,2]
b = [copy.copy(x) for i in range(3)]
print(id(b[0])) #140133864442248
print(id(b[1])) #140133864586120
print(id(b[2])) #140133864568008
print(b) #[[1, 2], [1, 2], [1, 2]] you can extend range to 256.
If you want a unique object and want to copy it from another object, try using copy. It makes a new object with the same values.
Edited again using one of my favorite function sum:
This is more or less redundant and it might confuse you some more, but sum also works too.
x = [1,2]
b = [sum([x],[]) for i in range(3)]
print(id(b[0])) #140692560200008
print(id(b[1])) #140692559012744
print(b) #[[1, 2], [1, 2], [1, 2]]
Will return different instances in the object. I only point this is just in case you don't want to import copy or import anything.
In the second case you're making what's known as a shallow copy of the [1,2] list. Essentially what that means is that somewhere in memory you have the list [1,2], and when you write [[1,2]]*2 you're saying you want two references to that same list. Thus, when you change one of the lists, you're actually changing the list that both items in b are referring to.
This is very-well understood behavior in Python.
a = [[], []] # two separate references to two separate lists
b = [] * 2 # two references to the same list object
a[0].append(1) # does not affect a[1]
b[0].append(1) # affects b[0] and b[1]

Append the same value multiple times to a list [duplicate]

This question already has answers here:
Creating a list in Python with multiple copies of a given object in a single line
(6 answers)
Closed 9 years ago.
To make my program more beautiful instead of ugly, I am trying to find a more pythonic way of adding a single value multiple times to a list. I now use a loop, but I create a variable I do not use.
l = []; n = 5; v = 0.5
for i in xrange(n):
l.append(v)
Any ideas?
To add v, n times, to l:
l += n * [v]
Try using list.extend and the multiply operator for lists
l.extend([v] * n)
The most general answer to this is to use list.extend() and a generator expression:
l.extend(generate_value() for _ in range(n))
This will add a value n times. Note that this will evaluate generate_value() each time, side-stepping issues with mutable values that other answers may have:
>>> [[1]] * 5
[[1], [1], [1], [1], [1]]
>>> _[0].append(1)
>>> _
[[1, 1], [1, 1], [1, 1], [1, 1], [1, 1]]
>>> [[1] for _ in range(5)]
[[1], [1], [1], [1], [1]]
>>> _[0].append(1)
>>> _
[[1, 1], [1], [1], [1], [1]]
When using the multiplication method, you end up with a list of n references to the same list. When you change it, you see the change in every element of the list - as they are all the same.
When using a generator expression or list comprehension, a new list is created for each sub-item, so each item is a different value. Modifying one only affects that one.
Obviously, in your example, the values are immutable, so this doesn't matter - but it's worth remembering for different cases, or if the values might not be immutable.
Try this
n = 5
v = 0.5
l = [v]*n

Python list problem [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
python:
m=[[0]*3]*2
for i in range(3):
m[0][i]=1
print m
I expect that this code should print
[[1, 1, 1], [0, 0, 0]]
but it prints
[[1, 1, 1], [1, 1, 1]]
This is by design. When you use multiplication on elements of a list, you are reproducing the references.
See the section "List creation shortcuts" on the Python Programming/Lists wikibook which goes into detail on the issues with list references to mutable objects.
Their recommended workaround is a list comprehension:
>>> s = [[0]*3 for i in range(2)]
>>> s
[[0, 0, 0], [0, 0, 0]]
>>> s[0][1] = 1
>>> s
[[0, 1, 0], [0, 0, 0]]
This is a bit devilish, but quite obvious when you understand what you're doing. when you're doing the [[0]*3]*2 bit, you're first creating a list with 3 zeros, then you copy that to make two elements. But when you do that copy, you do not create new lists with the same contents, but rather reference the same list several times. So when you change one, they all change.
An example to highlight it:
In [49]: s = [[]]*2 # Create two empty lists
In [50]: s # See:
Out[50]: [[], []]
In [51]: s[0].append(2) # Alter the first element (or so we think)
In [52]: s # OH MY, they both changed! (because they're the same list!)
Out[52]: [[2], [2]]

Categories