Python多维数组初始化的两种方式和浅拷贝问题

来源:互联网 发布:mac看不到隐藏文件夹 编辑:程序博客网 时间:2024/05/18 15:05

Python提供了列表、元组、字典等数据结构,列表可以进行多层嵌套,形成“多维数组”。
最近在Python中使用列表嵌套定义数组时遇到了浅拷贝的问题,对多维数组初始化的2种方法进行了总结。

1.[0]*n复制列表

  使用列表元素相乘的方式 [[[0]*a]*b]*n,初始化元素值为0的n维a*b数组。假设a=3,b=4,n=2,其初始化原理是将列表[0]复制3次成为[0,0,0],再将[0,0,0]列表对象的引用复制4次,得到初始化后的2维数组。
  值得注意的是,把[0,0,0]*4这种复制形式是一种浅拷贝。对于list中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说A[0][1]、A[1][1]、A[2][1]、A[3][1]对应的是同一个内存地址,当对A中元素A[0][1]进行修改时,对象A中的A[i][1]的值都会发生变化。

# 初始化一维listA=[0]*4A[0, 0, 0, 0]# 改变其中一个元素的值A[0]=1A[1, 0, 0, 0] #不影响列表中其他元素的值# 初始化一个2维的4×3的数组,嵌套的listA=[[0]*3]*4A[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]#改变数组中的元素的值#嵌套列表初始化之后,内层列表元素值的改变,会影响整个列表对象A的值A[0][1]=1A[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]A[1][1]=0A[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

2.通过循环赋初始值

通过for循环对列表进行赋值,逐个初始化元素为0。这种情况不会出现方法1中出现的浅拷贝问题。

B=[[0 for t in range(2)]for i in range(3)]B[[0, 0], [0, 0], [0, 0]]B[0][1]=1B[[0, 1], [0, 0], [0, 0]]

综上所述,通过循环赋初始值是一种比较推荐的初始化方法,不会因为对象引用的问题产生bug。
关于赋值、浅拷贝、深拷贝,可以用id()函数做实验,深入理解。id()函数可以返回对象的唯一编号,代表对象在python解释器中的内存地址。具体可参见这篇博客图解 Python 深拷贝和浅拷贝

# 方式1A=[0]*4print id(A)A=[[0]*3]*4print id(A)A[0][1]=1print id(A[0]),id(A[1])# 方式2B =[[0 for i in range(3)]for j in range(2)]print id(B[0]),id(B[1])

结果

# 方式1 列表内部的列表具有相同id,由此产生浅拷贝问题210971272 # id [0]*4138267400 # id [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]138267208 138267208  #id(A[0]),id(A[1])# 方式2 嵌套列表内部的列表具有不同的id210971720 210871240
原创粉丝点击