- 问题引入
a = [[0]*3 ] * 4
print(a)
a[0][0]=1
print(a)
初始化4行3列的二维数组,想把第一行和第一列的位置赋值为1
- 为何会这个样子?a[i][0]都变成1了
其实[]*N 这种方式初始化的数组,相当于只申请了一个地址空间。空间存储[0,0,0],然后二维数组的四个指针都指向同一个空间。无论修改哪一个,全部值都会改变。id()看下他们的物理位置都是一样的。 - python两种变量
Python 没有「变量」,我们平时所说的变量其实只是「标签」,是引用。
- 可变对象
对象指向的内存中的值会改变,当更改这个变量的时候,还是指向原来内存中的值,并且在原来的内存值进行原地修改,并没有开辟新的内存。例如列表List,字典dict,集合set。 - 不可变对象
对象所指向的内存中的值不能被改变,当改变这个变量的时候,原来指向的内存中的值不变,变量不再指向原来的值,而是开辟一块新的内存,变量指向新的内存。例如:数值类型int 、float;字符串str ;元组tuple;bool类型的对象。
所以对两种变量的引用赋值引起的结果是不一样的。开篇的问题就是由此引出。
- 只想赋值a[0][0],怎么做?
a=[[0]*3 for i in range(4)]
print(a)
a[0][0]=1
print(a)
上述写法每个一维数组都申请了一个内存空间。改变其中一个不会影响其他。
- 深拷贝和浅拷贝
- 浅拷贝 shallow copy
a = [0, [1, 2], 3]
b = a[:]
a[0] = 8
a[1][1] = 9
* 深拷贝 deep copy
import copy
a = [0, [1, 2], 3]
b = copy.deepcopy(a)
a[0] = 8
a[1][1] = 9
- 总结
- 没有限制条件的分片表达式(L[:])能够复制序列,但此法只能浅层复制。
- 字典 copy 方法,D.copy() 能够复制字典,但此法只能浅层复制
- 有些内置函数,例如 list,能够生成拷贝 list(L)
- copy 标准库模块能够生成完整拷贝:deepcopy 本质上是递归 copy
- 对于不可变对象和可变对象来说,浅复制都是复制的引用,只是因为复制不变对象和复制不变对象的引用是不等效的(因为对象不可变,当改变时会新建对象重新赋值)。所以看起来浅复制只复制不可变对象(整数,实数,字符串等),对于可变对象,浅复制其实是创建了一个对于该对象的引用,也就是说只是给同一个对象贴上了另一个标签而已。
- 这个文章讲得更详细
python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域