基础知识

在列表那一节的视频里我们给出了一个打印乘法表的例子,大概就是首先生成一个元素是列表的列表(列表的嵌套):

listTable1 = [[0] * 9 for i in range(9)]                (1)

想看看这个列表长啥样?print(listTable1)一下吧,结果出来是这样的:

[[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, 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, 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, 0, 0, 0, 0, 0, 0]]

看着有点晕,换个方式:

import pprint

pprint.pprint(listTable1)                            

这回的输出是这样婶的:

[[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, 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, 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, 0, 0, 0, 0, 0, 0]]

容易看了些吧,pprint的大名叫pretty print。[0] * 9,生成[0,0,0,0,0,0,0,0,0],这样的列表来9个(for i in range(9)),都放进一个大列表里,结果就成上面那样了。

变量初始化完毕,开始赋值,嵌套列表用嵌套循环来赋值:

for i in range(9):

    for j in range(9):

       listTable1[i][j] = (i+1) * (j+1)

pprint.pprint(listTable1) 漂漂滴输出下:

[[1, 2, 3, 4, 5, 6, 7, 8, 9],

 [2, 4, 6, 8, 10, 12, 14, 16, 18],

 [3, 6, 9, 12, 15, 18, 21, 24, 27],

 [4, 8, 12, 16, 20, 24, 28, 32, 36],

 [5, 10, 15, 20, 25, 30, 35, 40, 45],

 [6, 12, 18, 24, 30, 36, 42, 48, 54],

 [7, 14, 21, 28, 35, 42, 49, 56, 63],

 [8, 16, 24, 32, 40, 48, 56, 64, 72],

 [9, 18, 27, 36, 45, 54, 63, 72, 81]]

如果看那些中括号不顺眼,就:

for i in range(9):

    for j in range(9):

       print(listTable1[i][j], end=',')  

                # end=参数指定输出数据后加一个',',而不是回车

    print()    #一行输出完毕后换行

输出:

1, 2, 3, 4, 5, 6, 7, 8, 9,

 2, 4, 6, 8, 10, 12, 14, 16, 18,

 3, 6, 9, 12, 15, 18, 21, 24, 27,

 4, 8, 12, 16, 20, 24, 28, 32, 36,

 5, 10, 15, 20, 25, 30, 35, 40, 45,

 6, 12, 18, 24, 30, 36, 42, 48, 54,

 7, 14, 21, 28, 35, 42, 49, 56, 63,

 8, 16, 24, 32, 40, 48, 56, 64, 72,

 9, 18, 27, 36, 45, 54, 63, 72, 81,

 

假装分割线

 

你以为完了吗?其实并没有♪───O(≧∇≦)O────♪

有位朋友发来了一段程序(稍微改了下哈):

import pprint

listTable2 = [[0]*9]*9                    (1)        

for i in range(9):

    for j in range(9):

       listTable2[i][j] = (i+1) * (j+1)

pprint.pprint(listTable2)

不说结果,分析先哈,跟前面代码唯一的区别就是双重列表的定义这句:

listTable2 = [[0]*9]*9

[0]*9 ----->  [0,0,0,0,0,0,0,0,0],列表的乘法

继续[[0]*9]*9,也是列表的乘法,列表的元素也是列表[0,0,0,0,0,0,0,0,0],*9变成啥样了泥?漂漂打印下:pprint.pprint(listTable2)

输出结果如下:

[[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, 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, 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, 0, 0, 0, 0, 0, 0]]

跟前面的listTable1初始化后的输出一摸一样,而后又经过了跟前面代码一样的赋值和输出,输出的结果竟然是:

[[9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81],

 [9, 18, 27, 36, 45, 54, 63, 72, 81]]

沃特?!ᶘᵒᴥᵒᶅ 

CPU进水了吧(¬_¬)

两段代码的差异只在语句(1),所以就来对比下这两条语句的执行细节,pythontutor.com这个网站视频里介绍过,能可视化执行过程(只能是基础代码哈,引入第三方模块就怎么支持了),把两段代码分别输入编辑框并执行。

代码1:

 

listTable1 = [[0] * 9 for i in range(9)]

print(listTable1)

输入后点击Visualize Execution按钮,单步执行观察listTable1的值和内存分配

代码2:

listTable2 = [[0]*9]*9  

print(listTable1)

重复同样操作。

先来看listTable1的执行情况:

listTable1系统给分配了9*9=81 个单元,存储每个listTable1[i][j],各自独立,赋值互不影响,结果也是如我们所愿。

而listTable2则是:

用listTable2 = [[0]*9]*9这种方法系统只给分配了长度为9的列表单元,listTable[0]、listTable[1]、listTable[2]、……listTable[8]指向的是同一个一维列表,这就导致for循环:

for i in range(9):

    for j in range(9):

       listTable2[i][j] = (i+1) * (j+1)

后面的赋值一直覆盖前面的,留下的是最后的赋值[9, 18, 27, 36, 45, 54, 63, 72, 81],而输出只是把这个列表重复输出了9遍而已,结果就是我们看到的输出喽。

 

欢迎来PythonABC网站做客