您的位置:首页 > 编程语言 > Python开发

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

2015-08-31 09:52 507 查看
When trying to create a 2d list, I used to write in this way since it looks simple and easy.

[code]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.

[code]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

[code]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

[code]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

[code]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

[code]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

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


Test

[code]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

[code]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



Mothod 2

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


Test

[code]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

[code]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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: