Home > Net >  * operation in python for 2-d matrix initialization
* operation in python for 2-d matrix initialization

Time:11-17

You init a 2-d matrix like this

board = [[0] * width for _ in range(height)]

Instead of

board = [[0] * width] * height

as it creates the list once and every row references the same list.

Is it not the same in the first case, we still use * so each column in each row should reference the same element for a given row. But this is not the case, why?

CodePudding user response:

0 is immutable.

In itself, it is not the root cause of the seemingly different behavior. The real difference is that you don't intend to change value of 0 (since you can't), so don't really know that it would not have been the same for 0, if you had changed the value of one of them (if it were possible).

Note that this is the same for the outer iteration.

T=[[0]*3]*3
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

here, you can change T[0] without changing T[1].

T[0]=[1,2,3]
[[1, 2, 3], [0, 0, 0], [0, 0, 0]]

So, you shouldn't be surprise if changing T[0][0] doesn't change T[0][1] neither. If saying T[0][0]=5 still keeps T[0][1] at 2. No different behavior here.

Where the, seemingly, different behavior occurs, is when you are not changing T[0] but its content

T=[[0]*3]*3
T[0][0]=12
T
#[[12, 0, 0], [12, 0, 0], [12, 0, 0]]

But that is not the same thing! You changed the content of T[0] not T[0] itself.

So, if you want to compare what happens to the outer array with what happen to the inner one (that is your question: why the same thing doesn't happen with the inner array. Why changing one column doesn't impact another column. Why changing T[0][0] doesn't impact T[0][1]), you should compare with an operation like

T[0][0].content=5

That is an operation that does not change T[0][0] but its content. That change the value of the object 0 that is stored in T[0][0].

If such an operation were possible, then you would see

T=[[0]*3]*3
T[0][0].content=5
#[[5, 5, 5], [5, 5, 5], [5, 5, 5]]

But such an operation is not possible. Because 0 is immutable. And therefore you cannot perform an operation similar to changing the content of T[0]. And therefore you cannot have a surprising difference of behavior between 2 operations, since they are not at all the same operation. T[0][0] changes the content of T[0] but changes T[0][0] itself.

Simplification of the problem

I am aware that the previous argument may be hard to follow, because T[0] has 2 roles in it: it is both an array and an element of an array.

So, it may be easier to simplify the question.

Your question can somehow be reduced to the 4 (including 1 impossible) operations:

# Operation 1
T=[0]*3
T[0]=5
# T=[5,0,0]. T[1] is still 0

# Operation 2
T=[{'x':0}]*3
T[0]={'x':5}
# [{'x': 5}, {'x': 0}, {'x': 0}]

# Operation 3 (impossible)
T=[0]*3
T[0].content=5
# [5, 5, 5]

# Operation 4
T=[{'x':0}]*3
T[0]['x']=5
# [{'x': 5}, {'x': 5}, {'x': 5}]

Your question is "why in operation 1, only one element is changed, while in operation 4, all elements are changed".

And my answer is that you are comparing different things. Operation 1 (changing T[0]) is similar to operation 2. And in operation 2 also, only 1 element change.

Operation 4 (changing T[0]'s content) would be comparable to operation 3. If operation 3 were possible. But it is not. Because integers are immutable. If they weren't, then operation 3 would be possible, and then you would see that after such an operation, all elements would have changed also (that is all value of the 3 references to the same element)

Back to your example: changing T[0][0] is just operation 1, performed in array T[0], so it is normal that it does not impact other elements of T[0]. You have changed T[0][0] not just its content. But, from the point of view of array T, changing T[0][0] is also changing the content of T[0]. So like operation 4. So it is normal that it impacts other references of the same array, that are T[1] and T[2].

CodePudding user response:

See List of lists changes reflected across sublists unexpectedly

In  [1]: a = object()                                                                                                           
                                                                                                                                
In  [1]: [a] * 10                                                                                                               
Out [1]:                                                                                                                        
[<object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>,                                                                                                    
 <object at 0x7f57d0670a90>] 

When multiplying a list, the objects in the resulting list will be the same instance with the same id(). So [0] * width (a list) will be shared across all rows [0..height).

  • Related