前言: 这个专题主要记录一些在使用python过程中出现的一些自认为理所当然,但是实际情况与想象中差别很大的很神奇的状况,python虽然好用,但也是个调皮的小孩,有时候也会对我们开个小小的玩笑,故取名为 “python太调皮” 系列。

如果想新建并初始化一个全0的4行5列的list。可以有两种方式:

1、利用for循环

A1 = [[0 for i in range(5)]for j in range(4)] 
print(A1)#输出:[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

2、直接利用运算符号

A2 = [[0]*5]*4
print(A1)#输出:[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

从输出看,两者的结果是相同的,接下来我们看看他们的维数:

n1 = len(A1)#输出4
m1 = len(A1[0])#输出5

n2 = len(A2)#输出4
m2 = len(A2[0])#输出5

维数也是相同的,也就是说,外表看他两是一模一样的,貌似第二种方法代码还更简洁。但是,等等。。。让我们执行以下一句代码:

A1[0][2] = 1 
print('A1:',A1)
A2[0][2] = 1
print('A2:',A2)

神奇的事情发生了,我们本意上只是想改变[0][2]这个位置上元素的值,但是第二种方法创建的list竟然把整个列都改变了:

A1:[[0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
A2:[[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]]

这种错误匪夷所思,通过其他方面完全看不出来,一般很难找到的。最后,经过网上查找资料,发现了原因:第二种方法创建的[0] * 5是一个一维数组的对象,* 4之后只是把该对象的引用复制了4次,也就是说,我只要修改这个对象的一个值,所有的引用都会跟着变化。

以后再创建list的时候,还是老老实实用for循环比较靠谱。前期图一个小小的省事最后导致消耗大量的精力去解决bug。

附:另一个手残操作:

在一个做笔试的时候,还剩一分钟就提交了,对于一个list = [0.1,0.2,0.3,0.4]。想得到每个元素都乘以10的list,即list = [1,2,3,4]。于是手残写了这样一句代码:list = [0.1,0.2,0.3,0.4]*10 时间紧迫,根本没有办法找出错误,最终也没有正确提交上去(其实事后想起来,是一不小心“借鉴”了python中numpy包的广播机制)。

其实这个真正执行的结果只是将这个list复制了10次,变成了:

list = [0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4,0.1,0.2,0.3,0.4]

对于这种操作list中对应元素的方法,Python里只能使用以下两种方法:

  1. map()函数
list = map(lambda x :x*10,list)
def chage(x) :            # 计算平方数
	 return x * 10
map(chage, list)   # 计算列表各个元素的平方【注意这里的函数不需要传入参数,也不用括号】

但是需要注意,在python3中,这样返回了一个迭代器,并不是列表(如果接下来正好要使用for循环遍历这个列表返回迭代器也挺方便的)
2. for循环
使用这种方式,给程序一个列表,它会还你一个列表,比较常用。

list = [lambda i: i*10 for i in list]