1. 程式人生 > >Python, pitfall of creating 2d list, [foo*3]*3

Python, pitfall of creating 2d list, [foo*3]*3

When trying to create a 2d list, I used to write in this way since it looks simple and easy.

a =  [12*3]*3

I didn’t realize its undesirable side effect until solving one problem yesterday.

What is problem ?

if we are trying to change value of one element, the corresponding elem in each row will be modified.

a[0][0] = 10

The expected output should be

[ [10, 12, 12], [12, 12, 12], [12, 12, 12] ]

However, It actually becomes

[ [10, 12, 12], [10, 12, 12], [10, 12, 12] ]

The reason

1-D list

An experience is made to explain this problem. Here is a case for 1d list

a = [12]*5

print id(a)
print
id(a[0]), id(a[1]), id(a[4]) a[0] = 10 print a print id(a) print id(a[0]), id(a[1]), id(a[4])

output is

4148536204
141234284 141234284 141234284
[10, 12, 12, 12, 12]
4148536204
141234308 141234284 141234284

We notice that even if all elem in list have the same id, python will create a new object for a coming value because integer is immutable ( id(a[0]), id(a[1]) are different ).

2-D list

a = [[12]*3]*3

print id(a)
print id(a[0]), id(a[0][0]), id(a[0][1]), id(a[0][2])
print id(a[1]), id(a[1][0]), id(a[1][1]), id(a[1][2])
print id(a[2]), id(a[2][0]), id(a[2][1]), id(a[2][2])

print a 

a[0][0] = 10

print a 
print id(a)
print id(a[0]), id(a[0][0]), id(a[0][1]), id(a[0][2])
print id(a[1]), id(a[1][0]), id(a[1][1]), id(a[1][2])
print id(a[2]), id(a[2][0]), id(a[2][1]), id(a[2][2])

output is

4147959532
4147958668 152936556 152936556 152936556
4147958668 152936556 152936556 152936556
4147958668 152936556 152936556 152936556
[[12, 12, 12], [12, 12, 12], [12, 12, 12]]
[[10, 12, 12], [10, 12, 12], [10, 12, 12]]
4147959532
4147958668 152936580 152936556 152936556
4147958668 152936580 152936556 152936556
4147958668 152936580 152936556 152936556

The picture for illustrating this problem is shown below
這裡寫圖片描述

Although the list(id=4147958668) has been modified, all first elem in each list in 2D list are pointing to the first elem in list(id=4147958668). That is why all of them become 10.

How to solve it ?

Method 1

a = [x[:] for x in [[12]*3]*3]

Test

a = [[12]*3]*3

print id(a)
print id(a[0]), id(a[0][0]), id(a[0][1]), id(a[0][2])
print id(a[1]), id(a[1][0]), id(a[1][1]), id(a[1][2])
print id(a[2]), id(a[2][0]), id(a[2][1]), id(a[2][2])

print a 

a = [x[:] for x in [[12]*3]*3]
print id(a)
print id(a[0]), id(a[0][0]), id(a[0][1]), id(a[0][2])
print id(a[1]), id(a[1][0]), id(a[1][1]), id(a[1][2])
print id(a[2]), id(a[2][0]), id(a[2][1]), id(a[2][2])

Output is

4148614892
4148614028 158683244 158683244 158683244
4148614028 158683244 158683244 158683244
4148614028 158683244 158683244 158683244
[[12, 12, 12], [12, 12, 12], [12, 12, 12]]
4148613388
4148615500 158683244 158683244 158683244
4148615276 158683244 158683244 158683244
4148615308 158683244 158683244 158683244

If we use this method, we find a[0], a[1], a[2] have different addresses. The picture is shown below

Method2

Mothod 2

a = [[12 for x in range(3)] for y in range(3)]

Test

a = [[12 for x in range(3)] for y in range(3)]

print id(a)
print id(a[0]), id(a[0][0]), id(a[0][1]), id(a[0][2])
print id(a[1]), id(a[1][0]), id(a[1][1]), id(a[1][2])
print id(a[2]), id(a[2][0]), id(a[2][1]), id(a[2][2])

Output is

4148420908
4148422412 143655020 143655020 143655020
4148420876 143655020 143655020 143655020
4148423308 143655020 143655020 143655020

It’s the same method as method 1

Summary

The correct way to create 2D list are
python
a = [x[:] for x in [[12]*3]*3]
a = [[12 for x in range(3)] for y in range(3)]
a = [ [12]*3 for dummy in range(3) ]

the third one is in my favorite one.