《Python零基础入门学习-水木书荟》适合学习Python3的入门读者,也适用对编程一无所知,但渴望用编程改变世界的朋友们!《Python零基础入门学习-水木书荟》提倡理解为主,应用为王。因此,只要有可能,小甲鱼(作者)都会通过《Python零基础入门学习-水木书荟》中生动的实例来让大家理解概念。
虽然《《Python零基础入门学习-水木书荟》》是一本入门书籍,但《《Python零基础入门学习-水木书荟》》的“野心”可并不止于“初级水平”的教学。《《Python零基础入门学习-水木书荟》》前半部分是基础的语法特性讲解,后半部分围绕着Python3在爬虫、Tkinter和游戏开发等实例上的应用。
编程知识深似海,小甲鱼没办法仅通过《《Python零基础入门学习-水木书荟》》将所有的知识都灌输给你,但能够做到的是培养你对编程的兴趣,提高你编写代码的水平,以及锻炼你的自学能力。后,《《Python零基础入门学习-水木书荟》》贯彻的核心理念是: 实用、好玩,还有参与。
本书适合入门学习Python3的读者,也适用于对编程一无所知,但渴望用编程改变世界的朋友!本书提倡理解为主,应用为王。本书前半部分讲解Python3的基础语法和高级特性,后半部分围绕着Python3在爬虫、Tkinter和游戏开发等实例上的应用。本书着重培养读者对编程的兴趣,提高你编写代码的水平,以及锻炼读者的自学能力。后,本书贯彻的核心理念是:实用、好玩,还有参与。
目录
第1章就这么愉快地开始吧
1.1获得Python
1.2从IDLE启动Python
1.3失败的尝试
1.4尝试点儿新的东西
1.5为什么会这样
第2章用Python设计及时个游戏
2.1及时个小游戏
2.2缩进
2.3BIF
第3章成为高手前必须知道的一些基础知识
3.1变量
3.2字符串
3.3原始字符串
3.4长字符串
3.5改进我们的小游戏
3.6条件分支
3.7while循环
3.8引入外援
3.9闲聊数据类型
3.9.1整型
3.9.2浮点型
3.9.3布尔类型
3.9.4类型转换
3.9.5获得关于类型的信息
3.10常用操作符
3.10.1算术操作符
3.10.2优先级问题
3.10.3比较操作符
3.10.4逻辑操作符
第4章了不起的分支和循环
4.1分支和循环
4.2课堂小练习
4.3结果分析
4.4Python可以有效避免“悬挂else”
4.5条件表达式(三元操作符)
4.6断言
4.7while循环语句
4.8for循环语句
4.9range()
4.10break语句
4.11continue语句
第5章列表、元组和字符串
5.1列表: 一个“打了激素”的数组
5.1.1创建列表
5.1.2向列表添加元素
5.1.3从列表中获取元素
5.1.4从列表删除元素
5.1.5列表分片
5.1.6列表分片的进阶玩法
5.1.7一些常用操作符
5.1.8列表的小伙伴们
5.1.9关于分片“拷贝”概念的补充
5.2元组: 戴上了枷锁的列表
5.2.1创建和访问一个元组
5.2.2更新和删除元组
5.3字符串
5.3.1各种内置方法
5.3.2格式化
5.4序列
第6章函数
6.1Python的乐高积木
6.1.1创建和调用函数
6.1.2函数的参数
6.1.3函数的返回值
6.2灵活即强大
6.2.1形参和实参
6.2.2函数文档
6.2.3关键字参数
6.2.4默认参数
6.2.5收集参数
6.3我的地盘听我的
6.3.1函数和过程
6.3.2再谈谈返回值
6.3.3函数变量的作用域
6.4内嵌函数和闭包
6.4.1global关键字
6.4.2内嵌函数
6.4.3闭包(closure)
6.5lambda表达式
6.6递归
6.6.1递归是“神马”
6.6.2写一个求阶乘的函数
6.6.3这帮小兔崽子
6.6.4汉诺塔
第7章字典和集合
7.1字典: 当索引不好用时
7.1.1创建和访问字典
7.1.2各种内置方法
7.2集合: 在我的世界里,你就是
7.2.1创建集合
7.2.2访问集合
7.2.3不可变集合
第8章长期存储
8.1文件: 因为懂你,所以永恒
8.1.1打开文件
8.1.2文件对象的方法
8.1.3文件的关闭
8.1.4文件的读取和定位
8.1.5文件的写入
8.1.6一个任务
8.2文件系统: 介绍一个高大上的东西
8.3pickle: 腌制一缸美味的泡菜
第9章异常处理
9.1你不可能总是对的
9.2tryexcept语句
9.2.1针对不同异常设置多个except
9.2.2对多个异常统一处理
9.2.3捕获所有异常
9.3tryfinally语句
9.4raise语句
9.5丰富的else语句
9.6简洁的with语句
第10章图形用户界面入门
10.1导入EasyGui
10.2使用EasyGui
10.3修改默认设置
第11章类和对象
11.1给大家介绍对象
11.2对象=属性 方法
11.3面向对象编程
11.3.1self是什么
11.3.2你听说过Python的魔法方法吗
11.3.3公有和私有
11.4继承
11.4.1调用未绑定的父类方法
11.4.2使用super函数
11.5多重继承
11.6组合
11.7类、类对象和实例对象
11.8到底什么是绑定
11.9一些相关的BIF
第12章魔法方法
12.1构造和析构
12.1.1__init__(self[, ...])
12.1.2__new__(cls[, ...])
12.1.3__del__(self)
12.2算术运算
12.2.1算术操作符
12.2.2反运算
12.2.3增量赋值运算
12.2.4一元操作符
12.3简单定制
12.4属性访问
12.5描述符(property的原理)
12.6定制序列
12.7迭代器
12.8生成器(乱入)
第13章模块
13.1模块就是程序
13.2命名空间
13.3导入模块
13.4__name__='__main__'
13.5搜索路径
13.6包
13.7像个极客一样去思考
第14章论一只爬虫的自我修养
14.1入门
14.2实战
14.2.1下载一只猫
14.2.2翻译文本
14.3隐藏
14.3.1修改UserAgent
14.3.2延迟提交数据
14.3.3使用
14.4Beautiful Soup
14.5正则表达式
14.5.1re模块
14.5.2通配符
14.5.3反斜杠
14.5.4字符类
14.5.5重复匹配
14.5.6特殊符号及用法
14.5.7元字符
14.5.8贪婪和非贪婪
14.5.9反斜杠 普通字母=特殊含义
14.5.10编译正则表达式
14.5.11编译标志
14.5.12实用的方法
14.6异常处理
14.6.1URLError
14.6.2HTTPError
14.6.3处理异常
14.7安装Scrapy
14.8Scrapy爬虫之初窥门径
14.8.1Scrapy框架
14.8.2创建一个Scrapy项目
14.8.3定义Item容器
14.8.4编写爬虫
14.8.5爬
14.8.6取
14.8.7在Shell中尝试Selector选择器
14.8.8使用XPath
14.8.9提取数据
14.8.10使用item
14.8.11存储内容
第15章GUI的最终选择: Tkinter
15.1Tkinter之初体验
15.2Label组件
15.3Button组件
15.4Checkbutton组件
15.5Radiobutton组件
15.6LabelFrame组件
15.7Entry组件
15.8Listbox组件
15.9Scrollbar组件
15.10Scale组件
15.11Text组件
15.11.1Indexes用法
15.11.2Marks用法
15.11.3Tags用法
15.12Canvas组件
15.13Menu组件
15.14Menubutton组件
15.15OptionMenu组件
15.16Message组件
15.17Spinbox组件
15.18PanedWindow组件
15.19Toplevel组件
15.20事件绑定
15.21事件序列
15.21.1type
15.21.2modifier
15.22Event对象
15.23布局管理器
15.23.1pack
15.23.2grid
15.23.3place
15.24标准对话框
15.24.1messagebox(消息对话框)
15.24.2filedialog(文件对话框)
15.24.3colorchooser(颜色选择对话框)
第16章Pygame: 游戏开发
16.1安装Pygame
16.2初步尝试
16.3解惑
16.3.1什么是Surface对象
16.3.2将一个图像绘制到另一个图像上是怎么一回事
16.3.3移动图像是怎么一回事
16.3.4如何控制游戏的速度
16.3.5Pygame的效率高不高
16.3.6我应该从哪里获得帮助
16.4事件
16.5提高游戏的颜值
16.5.1显示模式
16.5.2全屏才是王道
16.5.3使窗口尺寸可变
16.5.4图像的变换
16.5.5裁剪图像
16.5.6转换图片
16.5.7透明度分析
16.6绘制基本图形
16.6.1绘制矩形
16.6.2绘制多边形
16.6.3绘制圆形
16.6.4绘制椭圆形
16.6.5绘制弧线
16.6.6绘制线段
16.7动画精灵
16.7.1创建精灵
16.7.2移动精灵
16.8碰撞检测
16.8.1尝试自己写碰撞检测函数
16.8.2sprite模块提供的碰撞检测函数
16.8.3实现碰撞检测
16.9播放声音和音效
16.10响应鼠标
16.10.1设置鼠标的位置
16.10.2自定义鼠标光标
16.10.3让小球响应光标的移动频率
16.11响应键盘
16.12结束游戏
16.12.1发生碰撞后获得随机速度
16.12.2减少“抖动”现象的发生
16.12.3游戏胜利
16.12.4更好地结束游戏
16.13经典飞机大战
16.13.1游戏设定
16.13.2主模块
16.13.3我方飞机
16.13.4响应键盘
16.13.5飞行效果
16.13.6敌方飞机
16.13.7提升敌机速度
16.13.8碰撞检测
16.13.9碰撞检测
16.13.10一个BUG
16.13.11发射子弹
16.13.12设置敌机“血槽”
16.13.13中弹效果
16.13.14绘制得分
16.13.15暂停游戏
16.13.16控制难度
16.13.17全屏炸弹
16.13.18发放补给包
16.13.19超级子弹
16.13.20三次机会
16.13.21结束画面
参考文献
第5章列表、元组和字符串
5.1列表: 一个“打了激素”的数组有时候需要把一堆东西暂时存储起来,因为它们有某种直接或者间接的联系,需要把它们放在某种“组”或者“集合”中,因为将来可能用得上。很多接触过编程的朋友都知道或者听说过数组。数组这个概念呢,就是把一大堆同种类型的数据挨个儿摆在一块儿,然后通过数组下标进行索引。但数组有一个基本要求,就是你所放在一起的数据必须类型一致。由于Python的变量没有数据类型,也就是说,Python是没有数组的。但是呢,Python加入了更为强大的列表。Python的列表有多强大?如果把数组比作是一个集装箱的话,那么Python的列表就是一个工厂的仓库了。列表真的非常有用,基本上所有的Python程序都要使用到列表,包括之前的打飞机游戏,里边的小飞机可以全部扔到一个列表中统一管理。5.1.1创建列表创建列表和创建普通变量一样,用中括号括起一堆数据就可以了,数据之间用逗号隔开,这样一个普普通通的列表就创建成功了:
number = [1, 2, 3, 4, 5]
我们说列表是打了激素的数组不是没有道理的,可以创建一个鱼龙混杂的列表:
mix = [1, "小甲鱼", 3.14, [1, 2, 3]]
可以看到上边这个列表里有整型、字符串、浮点型数据,甚至还可以包含着另一个列表。当然,如果实在想不到要往列表里边塞什么数据的时候,可以先创建一个空列表:
empty = []
5.1.2向列表添加元素列表相当灵活,所以它的内容不可能总是固定的,现在就来教大家如何向列表添加元素吧。要向列表添加元素,可以使用append()方法:
number = [1, 2, 3, 4, 5]
number.append(6)
number
[1, 2, 3, 4, 5, 6]
可以看到,参数6已经被添加到列表number的末尾了。有读者可能会问,这个方法调用怎么跟平时的BIF内置函数调用不一样呢?嗯,因为append()不是一个BIF,它是属于列表对象的一个方法。中间这个“.”,大家暂时可以理解为范围的意思: append()这个方法是属于一个叫作number的列表对象的。关于对象的知识,咱暂时只需要理解这么多,后边再给大家介绍对象。同理,我们可以把数字7和8添加进去,但是我们发现似乎不能用append()同时添加多个元素:
number.append(7, 8)
Traceback (most recent call last):
File "pyshell#122", line 1, in module
number.append(7, 8)
TypeError: append() takes exactly one argument (2 given)
这时候就可以使用extend()方法向列表末尾添加多个元素:
number.extend(7, 8)
Traceback (most recent call last):
File "pyshell#123", line 1, in module
number.extend(7, 8)
TypeError: extend() takes exactly one argument (2 given)
哎呀,怎么又报错了呢?!嗯,其实小甲鱼是故意的。extend()方法事实上使用一个列表来扩展另一个列表,所以它的参数应该是一个列表:
number.extend([7, 8])
number
[1, 2, 3, 4, 5, 6, 7, 8]
好,我们又再一次向世界证明我们成功了!但是又发现了一个问题,到目前为止,我们都是往列表的末尾添加数据,那如果我想“插队”呢?当然没问题,想要往列表的任意位置插入元素,就要使用insert()方法。insert()方法有两个参数: 及时个参数代表在列表中的位置,第二个参数是在这个位置处插入一个元素。不妨来试一下,让数字0出现在列表number的最前边:
number.insert(1, 0)
number
[1, 0, 2, 3, 4, 5, 6, 7, 8]
等等,不是说好插入到及时个位置吗?怎么插入后0还是排在1的后边呢?其实是这样的: 凡是顺序索引,Python均从0开始,同时这也是大多数编程语言约定俗成的规范。那么大家知道为什么要用0来表示及时个数吗?是因为计算机本身就是二进制的,在二进制的世界里只有两个数: 0和1,当然,0就是二进制里的及时个数了,所以嘛,秉承着这样的传统,0也就习惯用于表示及时个数。所以,正确的做法应该是:
number = [1, 2, 3, 4, 5, 6, 7, 8]
number.insert(0, 0)
number
[0, 1, 2, 3, 4, 5, 6, 7, 8]
5.1.3从列表中获取元素跟数组一样,可以通过元素的索引值(index)从列表获取单个元素,注意,列表索引值是从0开始的:
name = ["鸡蛋", "鸭蛋", "鹅蛋", "李狗蛋"]
name[0]
'鸡蛋'
name[3]
'李狗蛋'
那按照这个方法让“李狗蛋”和“鸭蛋”的位置互调:
name[1], name[3] = name[3], name[1]
name
['鸡蛋', '李狗蛋', '鹅蛋', '鸭蛋']
5.1.4从列表删除元素从列表删除元素,这里也介绍三种方法: remove()、del和pop()。先演示一下用remove()删除元素:
name.remove("李狗蛋")
name
['鸡蛋', '鹅蛋', '鸭蛋']
使用remove()删除元素,你并不需要知道这个元素在列表中的具体位置,只需要知道该元素存在列表中就可以了。如果要删除的东西根本不在列表中,程序就会报错:
name.remove("陈鸭蛋")
Traceback (most recent call last):
File "pyshell#138", line 1, in module
name.remove("陈鸭蛋")
ValueError: list.remove(x): x not in list
remove()方法并不能指定删除某个位置的元素,这时就要用del来实现:
del name[1]
name
['鸡蛋', '鸭蛋']
注意,del是一个语句,不是一个列表的方法,所以你不必在它后边加上小括号()。另外,如果你想删除整个列表,还可以直接用del加列表名删除:
del name
name
Traceback (most recent call last):
File "pyshell#142", line 1, in module
name
NameError: name 'name' is not defined
,演示用pop()方法“弹出”元素:
name = ["鸡蛋", "鸭蛋", "鹅蛋", "李狗蛋"]
name.pop()
'李狗蛋'
name.pop()
'鹅蛋'
name
['鸡蛋', '鸭蛋']
大家看到了,pop()方法默认是弹出列表中的一个元素。但这个pop()方法其实还可以灵活运用,当你为它加上一个索引值作为参数的时候,它会弹出这个索引值对应的元素:
name = ["鸡蛋", "鸭蛋", "鹅蛋", "李狗蛋"]
name.pop(2)
'鹅蛋'
name
['鸡蛋', '鸭蛋', '李狗蛋']
5.1.5列表分片利用索引值,每次可以从列表获取一个元素,但是人总是贪心的,如果需要一次性获取多个元素,有没有办法实现呢?利用列表分片(slice),可以方便地实现这个要求:
name = ["鸡蛋", "鸭蛋", "鹅蛋", "李狗蛋"]
name[0:2]
['鸡蛋', '鸭蛋']
很简单对吧?只不过是用一个冒号隔开两个索引值,左边是开始位置,右边是结束位置。这里要注意的一点是,结束位置上的元素是不包含的。利用列表分片,得到一个原来列表的拷贝,原来列表并没有发生改变。列表分片也可以简写,我们说过Python就是以简洁闻名于世,所以你能想到的“便捷方案”,Python的作者以及Python社区的小伙伴们都已经想到了,并付诸实践,你要做的就是验证一下是否可行:
name[:2]
['鸡蛋', '鸭蛋']
name[1:]
['鸭蛋', '鹅蛋', '李狗蛋']
name[:]
['鸡蛋', '鸭蛋', '鹅蛋', '李狗蛋']
如果没有开始位置,Python会默认开始位置是0。同样道理,如果要得到从指定索引值到列表末尾的所有元素,把结束位置省去即可。如果没有放入任何索引值,而只有一个冒号,将得到整个列表的拷贝。再一次强调: 列表分片就是建立原列表的一个拷贝(或者说副本),所以如果你想对列表做出某些修改,但同时还想保持原来的那个列表,那么直接使用分片的方法来获取拷贝就很方便了。5.1.6列表分片的进阶玩法分片操作实际上还可以接收第三个参数,其代表的是步长,默认情况下(不指定它的时候)该值为1,来试试将其改成2会有什么效果?
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list1[0:9:2]
[1, 3, 5, 7, 9]
如果将步长改成2,那么每前进两个元素才取一个出来。其实还可以直接写成list1[::2]。如果步长的值是负数,例如-1,结果会怎样呢?不妨试试看:
list1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
是不是很有意思?这里步长设置为-1,就相当于复制一个反转的列表。5.1.7一些常用操作符
此前学过的大多数操作符都可以运用到列表上:
list1 = [123]
list2 = [234]
list1 list2
False
list3 = ['abc']
list4 = ['bcd']
list3 list4
True
我们发现列表还是挺聪明的,竟然会懂得比较大小。那如果列表中不止一个元素呢?结果又会如何?
list1 = [123, 456]
list2 = [234, 123]
list1 list2
False
怎么会这样?list1列表的和是123 456=579,按理应该比list2列表的和234 123=357要大,为什么list1>list2还会返回False呢?思考片刻后得出结论: Python的列表原来并没有我们想象中那么“智能”(注: 在后边讲“魔法方法”的章节会教大家如何把列表改变得更加聪明),当列表包含多个元素的时候,默认是从及时个元素开始比较,只要有一个PK赢了,就算整个列表赢了。字符串比较也是同样的道理(字符串比较的是及时个字符对应的ASCII码值的大小)。我们知道字符串可以用加号( )来进行拼接,用乘号()来复制自身若干次。它们在列表身上也是可以实现的:
list1 = [123, 456]
list2 = [234, 123]
list3 = list1 list2
list3
[123, 456, 234, 123]
加号( )也叫连接操作符,它允许我们把多个列表对象合并在一起,其实就相当于extend()方法实现的效果。一般情况下建议大家使用extend()方法来扩展列表,因为这样显得更为规范和专业。另外,连接操作符并不能实现列表添加新元素的操作:
list1 = [123, 456]
list2 = list1 789
Traceback (most recent call last):
File "pyshell#177", line 1, in module
list2 = list1 789
TypeError: can only concatenate list (not "int") to list
所以如果要添加一个元素到列表中,用什么方法?嗯,可以用append()或者insert()方法,希望大家还记得。乘号()也叫重复操作符,重复操作符可以用于列表中:
list1 = [123]
list1 3
[123, 123, 123]
当然复合赋值运算符也可以用于列表:
list1 = 5
list1
[123, 123, 123, 123, 123]
另外有个成员关系操作符大家也不陌生,我们是在谈for循环的时候认识它的,成员关系操作符就是in和not in!
list1 = ["小猪", "小猫", "小狗", "小甲鱼"]
"小甲鱼" in list1
True
"小护士" not in list1
True
之前说过列表里边可以包含另一个列表,那么对于列表中的列表元素,能不能使用in和not in测试呢?试试便知:
list1 = ["小猪", "小猫", ["小甲鱼", "小护士"], "小狗"]
"小甲鱼" in list1
False
"小护士" not in list1
True
可见,in和not in只能判断一个层次的成员关系,这跟break和continue语句只能跳出一个层次的循环是一个道理。那要判断列表里边的列表的元素,应该先进入一层列表:
"小甲鱼" in list1[2]
True
"小护士" not in list1[2]
False
顺便说一下,前面提到使用索引号去访问列表中的值,那么对于列表中的值,应该如何访问呢?大家应该猜到了,其实跟C语言访问二维数组的方法相似:
list1[2][0]
'小甲鱼'
5.1.8列表的小伙伴们接下来认识一下列表的小伙伴们,那么列表有多少小伙伴呢?不妨让Python自己告诉我们:
dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
产生了一个熟悉又陌生的列表,很多熟悉的方法似曾相识,例如append()、extend()、insert()、pop()、remove()都是学过的。现在再给大家介绍几个常用的方法。count()这个方法的作用是计算它的参数在列表中出现的次数:
list1 = [1, 1, 2, 3, 5, 8, 13, 21]
list1.count(1)
2
index()这个方法会返回它的参数在列表中的位置:
list1.index(1)
可以看到,这里是返回及时个目标(1)在list1中的位置,index()方法还有两个参数,用于限定查找的范围。因此可以这样查找第二个目标在list1的位置:
start = list1.index(1) 1
stop = len(list1)
list1.index(1, start, stop)
1
reverse()方法的作用是将整个列表原地翻转,就是排的放到最前边,排最前的放到,那么排倒数第二的就排在第二,以此类推:
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
list1.reverse()
list1
[8, 7, 6, 5, 4, 3, 2, 1]
sort()这个方法是用指定的方式对列表的成员进行排序,默认不需要参数,从小到大排队:
list1 = [8, 9, 3, 5, 2, 6, 10, 1, 0]
list1.sort()
list1
[0, 1, 2, 3, 5, 6, 8, 9, 10]
那如果需要从大到小排队呢?很简单,先调用sort()方法,列表会先从小到大排好队,然后调用reverse()方法原地翻转就可以啦。什么?太麻烦?好吧,大家真是越来越懒了……很好,大家离天才又近了一步小甲鱼个人认为“懒”是创新发明的根源和动力。。其实,sort()这个方法其实有三个参数,其形式为sort(func, key, reverse)。func和key参数用于设置排序的算法和关键字,默认是使用归并排序,算法问题不在这里讨论,有兴趣的朋友可以看一下小甲鱼另一本不错的教程: 《数据结构和算法》(C语言)。这里要讨论sort()方法的第三个参数: reverse,没错,就是刚刚学的那个reverse()方法的那个reverse。不过这里作为sort()的一个默认参数,它的默认值是sort(reverse=False),表示不颠倒顺序。因此,只需要把False改为True,列表就相当于从大到小排序:
list1 = [8, 9, 3, 5, 2, 6, 10, 1, 0]
list1.sort(reverse=True)
list1
[10, 9, 8, 6, 5, 3, 2, 1, 0]
5.1.9关于分片“拷贝”概念的补充上一节提到使用分片创建列表的拷贝:
list1 = [1, 3, 2, 9, 7, 8]
list2 = list1[:]
list2
[1, 3, 2, 9, 7, 8]
list3 = list1
list3
[1, 3, 2, 9, 7, 8]
看似一样,对吧?但事实上呢?利用列表的一个小伙伴做以下修改,大家看看差别:
list1.sort()
list1
[1, 2, 3, 7, 8, 9]
list2
[1, 3, 2, 9, 7, 8]
list3
[1, 2, 3, 7, 8, 9]
可以看到list1已经从小到大排好了序,那list2和list3呢?使用分片方式得到的list2很有原则、很有格调,并不会因为list1的改变而改变,这个原理我待会儿跟大家说; 接着看list3……看,真正的墙头草是list3,它竟然跟着list1改变了,这是为什么呢?不知道大家还记不记得在讲解变量的时候说过,Python的变量就像一个标签,就一个名字而已……还是给大家画个图好理解,如图51所示。
图51拷贝列表
这下大家应该