今天遇到一个list初始化的问题。
初始化一个5×5的二维数组:
>>>a = [[1] * 5]*5
>>>a
[[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
下面对a[0][0]的值进行修改:
>>> a[0][0]=10
>>> a
[[10, 1, 1, 1, 1], [10, 1, 1, 1, 1], [10, 1, 1, 1, 1], [10, 1, 1, 1, 1], [10, 1, 1, 1, 1]]
发现为什么这一列的值都修改了?百思不得其姐!查阅资料
原因在于a = [[1]*5]*5后面的四行其实是对第一行的引用。
正常情况下应该这样:
>>> a = [[1 for _ in range(5)] for _ in range(5)]#这里是重新开辟的空间,而上面是引用
>>> a
[[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
>>> a[0][0] = 8
>>> a
[[8, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
文档里面有写
What has happened is that [[]] is a one-element list containing an empty list,
so all three elements of [[]] * 3 are references to this single empty list.
Modifying any of the elements of lists modifies this single list. You can create a list of different lists this way:
>>> lists = [[] for i in range(3)]
>>> lists[0].append(3)
>>> lists[1].append(5)
>>> lists[2].append(7)
>>> lists
[[3], [5], [7]]
延伸一下copy和deepcopy的问题。
举个例子,请问打印的aaa.a和aaa.a_b.b的值分别是多少?
class AAA():
def __init__(self,a=0):
self.a = a
self.a_b = BBB()
class BBB():
def __init__(self,b=0):
self.b = b
aaa = AAA(10)
bbb = aaa
bbb.a = 9
print(aaa.a)
bbb.a_b.b = 8
print(aaa.a_b.b)
#这里aaa.a应该是9,aaa.a_b.b应该是8
上面这个其实很好理解,就是bbb直接引用aaa,bbb中改变之后,aaa中也被改变了。
下面开始升级版,请问aaa.a和aaa.a_b.b的值是多少:
import copy
class AAA():
def __init__(self,a=0):
self.a = a
self.a_b = BBB()
class BBB():
def __init__(self,b=0):
self.b = b
aaa = AAA(10)
bbb = copy.copy(aaa)
bbb.a = 9
print(aaa.a)
bbb.a_b.b = 8
print(aaa.a_b.b)
#这里aaa.a应该是10,aaa.a_b.b应该是8
其实copy通常叫做浅copy,也就是在赋值更改时,只对浅层的值进行复制(完全独立),对深层的值仍然是引用,bbb.a_b改变之后,aaa.a_b也会随着改变。
那么,现在下面的aaa.a和aaa.a_b.b的值又是多少呢?
import copy
class AAA():
def __init__(self,a=0):
self.a = a
self.a_b = BBB()
class BBB():
def __init__(self,b=0):
self.b = b
aaa = AAA(10)
bbb = copy.deepcopy(aaa)
bbb.a = 9
print(aaa.a)
bbb.a_b.b = 8
print(aaa.a_b.b)
这里aaa.a应该是10,aaa.a_b.b应该是0
deepcopy才是真正意义上的完全复制,复制之后和原来的对象和值没有任何关系。
同时,嵌套的list,也存在同样的情况,不再赘述。
>>> import copy
>>> a = [1,2,3,[1,2,3]]
>>> b = copy.copy(a)
>>> b[0] = 10
>>> b[3][0] = 10
>>> a
[1, 2, 3, [10, 2, 3]]
>>> b = copy.deepcopy(a)
>>> b[0] = 10
>>> b[3][0] = 10
>>> b
[10, 2, 3, [10, 2, 3]]