BLOG
Enjoy when you can, and endure when you must.
DEC 08, 2013/Python
注意Python的共享引用

Python中的共享引用是随处可见的,这也就意味着随时注意该行为是非常重要的,否则就可能出错。

假设我们需要创建一个大小为5x5的矩阵并以数字0对矩阵进行初始化,根据Python的一些特点和使用技巧,很可能会这样来做:

>>> matrix = [[0] * 5] * 5
>>> for row in matrix:
	print row

[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]

这看似很有效,不过假如对其中一位赋值的话:

>>> matrix[0][0] = 'hello'
>>> for row in matrix:
	print row

['hello', 0, 0, 0, 0]
['hello', 0, 0, 0, 0]
['hello', 0, 0, 0, 0]
['hello', 0, 0, 0, 0]
['hello', 0, 0, 0, 0]

问题就出现了,那剖析创建矩阵的方法[[0] * 5] * 5,这其中实际分为两个步骤。首先为创建行:

>>> row = [0] * 5
>>> row
[0, 0, 0, 0, 0]

也就是说row列表中的5个子项都引用0。之后的操作:

>>> matrix = [row] * 5

这就相当于引用了5次列表row。而问题就出在这里。虽然两次操作都是引用,但内层的引用是数字0,为不可变对象。而外层引用是可变对象列表。即一旦对列表进行修改,那就变成“全局修改”了。

因此这里需要避免的就是避开对列表的引用,保证每行互不引用就可以解决该问题。也就是说,总是去创建列表。

>>> matrix = [[0] * 5 for row in range(5)]
>>> for row in matrix:
	print row

['hello', 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]

所以说理解Python的这些特性是很重要的。

COMMENTS
LEAVE COMMNT