描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302507161
JetBrains官方推荐图书!JetBrains官大中华区市场部经理赵磊作序!送2400分钟同步视频课程!500个案例,400道Python练习题,电子书,10万行源代码,6个实战项目!
李宁 “私房菜谱”:
? Python语法基础
? Python高级编程
? Python Web开发
? Python科学计算与数据分析
? Python Web爬虫技术
? Python项目实战
李宁“实战项目”:
? Web项目实战:基于Flask的美团网
? Web项目实战:基于Django的58同城
? 爬虫项目实战:天气预报服务API
? 爬虫项目实战:胸罩销售数据分析
? GUI项目实战:动态修改域名指向的IP
? 游戏项目实战:俄罗斯方块
本书从实战角度系统讲解了Python核心知识点以及Python在Web开发、数据分析、网络爬虫、桌面应用等领域的各种开发实践。本书用超过5万行的代码及大量的实战案例完美演绎了Python在各个领域的出色表现,每一个案例都有详细的实现步骤,带领读者由浅入深系统掌握Python语言的核心及Python全栈开发技能。本书共分六篇,各篇内容如下:
Python基础知识篇(第1章~第10章),内容主要包括Python的基本概念、开发环境安装和配置、Python语言的基础知识,控制语句、列表、元组、字符串、字典、函数、类、对象、异常、方法、属性和迭代器;Python高级编程篇(第11章~第20章),内容主要包括正则表达式、常用模块、文件和流、数据存储、TCP和UDP编程、Urllib3、twisted、FTP、Email、多线程、tkinter、PyQt5和测试;Python Web开发篇(第21章、第22章),主要讲解了Python语言中*流行的两个Web开发框架(Flask和Django)的使用方法;Python科学计算与数据分析篇(第23章~第25章),主要讲解了Python语言中*常用的3个数据分析和数据可视化库(NumPy、Matplotlib和Pandas)的使用方法;Python Web爬虫技术篇(第26章、第27章),主要讲解了编写网络爬虫的关键技术和常用程序库,这些程序库主要包括Beautiful Soup和Scrapy;Python项目实战篇(第28章~第33章),内容主要包括Web项目开发实战、爬虫项目开发实战、API项目开发实战、桌面应用项目开发实战和游戏项目开发实战。
本书适合作为Python程序设计者的参考用书。
推荐序. 1
前言. 3
本书配套资源. 5
篇 Python基础知识
第1章 初识Python 3
1.1 Python简介. 3
1.1.1 什么是Python 3
1.1.2 Python的应用领域. 4
1.1.3 如何学好Python 5
1.1.4 Python API文档. 6
1.2 搭建Python开发环境. 8
1.2.1 安装官方的Python运行环境. 9
1.2.2 配置PATH环境变量. 11
1.2.3 安装Anaconda Python开发环境. 13
1.2.4 下载和安装JDK 13
1.2.5 下载和安装Eclipse 16
1.2.6 Python IDE(PyDev)安装. 17
1.2.7 配置Python IDE(PyDev)开发环境. 20
1.2.8 测试Python IDE(PyDev)开发环境. 21
1.2.9 安装PyCharm 22
1.2.10 配置PyCharm 23
1.2.11 Python中的REPL环境. 25
1.3 个Python程序. 26
1.4 调试Python程序. 26
1.5 小结. 29
1.6 实战与练习. 29
第2章 Python语言基础. 30
2.1 Python程序中的基本要素. 30
2.1.1 导入Python模块. 30
2.1.2 声明变量. 32
2.1.3 清空Python控制台. 32
2.2 数字. 34
2.2.1 基础知识. 34
2.2.2 大整数. 36
2.2.3 二进制、八进制和十六进制. 36
2.2.4 数字的格式化输出. 37
2.3 获取用户输入. 39
2.4 函数. 40
2.5 注释. 41
2.6 字符串基础. 42
2.6.1 单引号字符串和转义符. 42
2.6.2 拼接字符串. 43
2.6.3 保持字符串的原汁原味. 44
2.6.4 长字符串. 46
2.7 小结. 47
2.8 实战与练习. 47
第3章 条件、循环和其他语句. 49
3.1 神奇的print函数. 49
3.2 有趣的赋值操作. 51
3.3 用缩进创建代码块. 53
3.4 条件和条件语句. 53
3.4.1 布尔值和布尔变量. 54
3.4.2 条件语句(if、else和elif). 55
3.4.3 嵌套代码块. 56
3.4.4 比较运算符. 57
3.4.5 断言. 60
3.5 循环. 62
3.5.1 while循环. 62
3.5.2 for循环. 63
3.5.3 跳出循环. 65
3.5.4 循环中的else语句. 67
3.6 使用exec和eval执行求值字符串. 69
3.7 小结. 71
3.8 实战与练习. 71
第4章 列表和元组. 73
4.1 定义序列. 73
4.2 序列的基本操作. 74
4.2.1 通过索引操作序列元素. 74
4.2.2 分片. 77
4.2.3 序列相加. 83
4.2.4 序列的乘法. 84
4.2.5 检查某个值是否属于一个序列. 85
4.2.6 序列的长度、值和小值. 86
4.3 列表的基本操作. 87
4.4 列表方法. 89
4.5 元组. 93
4.6 小结. 95
4.7 实战与练习. 95
第5章 字符串…………………………………………………………………………. 97
5.1 字符串的基本操作. 97
5.2 格式化字符串. 98
5.2.1 字符串格式化基础. 98
5.2.2 模板字符串. 100
5.2.3 字符串的format方法. 101
5.2.4 更进一步控制字符串格式化参数. 102
5.2.5 字段宽度、精度和千位分隔符. 104
5.2.6 符号、对齐、用0填充和进制转换. 105
5.3 字符串方法. 107
5.3.1 center方法. 107
5.3.2 find方法. 108
5.3.3 join方法. 109
5.3.4 split方法. 110
5.3.5 lower方法、upper方法和capwords函数. 111
5.3.6 replace方法. 112
5.3.7 strip方法. 112
5.3.8 translate方法与maketrans方法. 113
5.4 小结. 114
5.5 实战与练习. 115
第6章 字典. 116
6.1 为什么要引入字典. 116
6.2 创建和使用字典. 117
6.2.1 dict函数. 117
6.2.2 字典的基本操作. 118
6.2.3 字典的格式化字符串. 120
6.2.4 序列与迭代. 121
6.3 字典方法. 124
6.3.1 clear方法. 124
6.3.2 copy方法与deepcopy函数. 125
6.3.3 fromkeys方法. 126
6.3.4 get方法. 127
6.3.5 items方法和keys方法. 128
6.3.6 pop方法和popitem方法. 129
6.3.7 setdefault方法. 130
6.3.8 update方法. 131
6.3.9 values方法. 132
6.4 小结. 133
6.5 实战与练习. 133
第7章 函数. 134
7.1 懒惰是重用的基石. 134
7.2 函数基础. 136
7.2.1 创建函数. 136
7.2.2 为函数添加文档注释. 137
7.2.3 没有返回值的函数. 138
7.3 函数参数. 139
7.3.1 改变参数的值. 139
7.3.2 关键字参数与默认值. 144
7.3.3 可变参数. 147
7.3.4 将序列作为函数的参数值. 151
7.4 作用域. 154
7.5 递归. 156
7.6 小结. 158
7.7 实战与练习. 158
第8章 类和对象. 159
8.1 对象的魔法. 159
8.2 类. 160
8.2.1 创建自己的类. 160
8.2.2 方法和私有化. 161
8.2.3 类代码块. 163
8.2.4 类的继承. 164
8.2.5 检测继承关系. 165
8.2.6 多继承. 167
8.2.7 接口. 169
8.3 小结. 170
8.4 实战与练习. 171
第9章 异常. 172
9.1 什么是异常. 172
9.2 主动抛出异常. 173
9.2.1 raise语句. 173
9.2.2 自定义异常类. 175
9.3 捕捉异常. 176
9.3.1 try…except语句的基本用法. 176
9.3.2 捕捉多个异常. 177
9.3.3 用同一个代码块处理多个异常. 179
9.3.4 捕捉对象. 180
9.3.5 异常捕捉中的else子句. 182
9.3.6 异常捕捉中的finally子句. 183
9.4 异常、函数与栈跟踪. 185
9.5 异常的妙用. 186
9.6 小结. 188
9.7 实战与练习. 188
第10章 方法、属性和迭代器. 189
10.1 构造方法. 189
10.1.1 构造方法的基础知识. 189
10.1.2 重写普通方法和构造方法. 190
10.1.3 使用super函数. 193
10.2 特殊成员方法. 194
10.2.1 自定义序列. 194
10.2.2 从内建列表、字符串和字典继承. 197
10.3 属性. 199
10.3.1 传统的属性. 199
10.3.2 property函数. 201
10.3.3 监控对象中所有的属性. 203
10.4 静态方法和类方法. 205
10.5 迭代器. 207
10.5.1 自定义可迭代的类. 207
10.5.2 将迭代器转换为列表. 209
10.6 生成器. 210
10.6.1 创建生成器. 210
10.6.2 递归生成器. 212
10.7 小结. 213
10.8 实战与练习. 214
第二篇 Python高级编程
第11章 正则表达式. 217
11.1 在Python语言中使用正则表达式. 217
11.1.1 使用match方法匹配字符串. 217
11.1.2 使用search方法在一个字符串中查找模式. 218
11.1.3 匹配多个字符串. 219
11.1.4 匹配任何单个字符. 220
11.1.5 使用字符集. 221
11.1.6 重复、可选和特殊字符. 223
11.1.7 分组. 226
11.1.8 匹配字符串的起始和结尾以及单词边界. 228
11.1.9 使用findall和finditer查找每一次出现的位置. 229
11.1.10 用sub和subn搜索与替换. 230
11.1.11 使用split分隔字符串. 232
11.2 一些常用的正则表达式. 232
11.3 小结. 233
11.4 实战与练习. 234
第12章 常用模块. 235
12.1 sys模块. 235
12.2 os模块. 238
12.2.1 获取与改变工作目录. 238
12.2.2 文件与目录操作. 239
12.2.3 软链接与硬链接. 240
12.2.4 杂项. 241
12.3 集合、堆和双端队列(heap模块、deque类). 243
12.3.1 集合. 244
12.3.2 堆. 247
12.3.3 双端队列. 249
12.4 时间、日期与日历(time模块). 250
12.4.1 时间元组. 250
12.4.2 格式化日期和时间. 251
12.4.3 时间戳的增量. 253
12.4.4 计算日期和时间的差值. 254
12.4.5 获取某月和某年的日历. 255
12.5 随机数(random模块). 256
12.6 数学(math模块). 257
12.7 小结. 258
12.8 实战与练习. 258
第13章 文件和流. 259
13.1 打开文件. 259
13.2 操作文件的基本方法. 260
13.2.1 读文件和写文件. 261
13.2.2 管道输出. 262
13.2.3 读行和写行. 264
13.3 使用FileInput对象读取文件. 265
13.4 小结. 266
13.5 实战与练习. 266
第14章 数据存储. 268
14.1 处理XML格式的数据. 268
14.1.1 读取与搜索XML文件. 268
14.1.2 字典转换为XML字符串. 270
14.1.3 XML字符串转换为字典. 272
14.2 处理JSON格式的数据. 273
14.2.1 JSON字符串与字典互相转换. 273
14.2.2 将JSON字符串转换为类实例. 275
14.2.3 将类实例转换为JSON字符串. 276
14.2.4 类实例列表与JSON字符串互相转换. 277
14.3 将JSON字符串转换为XML字符串. 278
14.4 SQLite数据库. 279
14.4.1 管理SQLite数据库. 279
14.4.2 用Python操作SQLite数据库. 281
14.5 MySQL数据库. 284
14.6 ORM 286
14.6.1 SQLAlchemy 287
14.6.2 SQLObject 291
14.7 非关系型数据库. 294
14.7.1 NoSQL简介. 294
14.7.2 MongoDB数据库. 295
14.7.3 pymongo模块. 296
14.8 小结. 297
14.9 实战与练习. 297
第15章 TCP与UDP编程. 299
15.1 套接字. 299
15.1.1 建立TCP服务端. 299
15.1.2 服务端接收数据的缓冲区. 303
15.1.3 服务端的请求队列. 305
15.1.4 TCP时间戳服务端. 307
15.1.5 用Socket实现HTTP服务器. 307
15.1.6 客户端Socket 311
15.1.7 UDP时间戳服务端. 312
15.1.8 UDP时间戳客户端. 313
15.2 socketserver模块. 314
15.2.1 实现socketserver TCP时间戳服务端. 314
15.2.2 实现socketserver TCP时间戳客户端. 315
15.3 小结. 316
15.4 实战与练习. 316
第16章 网络高级编程. 317
16.1 urllib3模块. 317
16.1.1 发送HTTP GET请求. 318
16.1.2 发送HTTP POST请求. 319
16.1.3 HTTP请求头. 320
16.1.4 HTTP响应头. 322
16.1.5 上传文件. 323
16.1.6 超时. 325
16.2 twisted框架. 326
16.2.1 异步编程模型. 327
16.2.2 Reactor(反应堆)模式. 329
16.2.3 HelloWorld(twisted框架). 329
16.2.4 用twisted实现时间戳客户端. 331
16.2.5 用twisted实现时间戳服务端. 332
16.2.6 用twisted获取Email邮箱目录列表. 333
16.3 FTP客户端. 338
16.4 Email客户端. 341
16.4.1 使用SMTP发送简单的Email 341
16.4.2 使用SMTP发送带附件的Email 343
16.4.3 使用POP3接收Email 344
16.4.4 使用IMAP4接收Email 346
16.5 小结. 348
16.6 实战与练习. 348
第17章 多线程. 349
17.1 线程与进程. 349
17.1.1 进程. 349
17.1.2 线程. 349
17.2 Python与线程. 350
17.2.1 使用单线程执行程序. 350
17.2.2 使用多线程执行程序. 351
17.2.3 为线程函数传递参数. 352
17.2.4 线程和锁. 353
17.3 高级线程模块. 355
17.3.1 Thread类与线程函数. 355
17.3.2 Thread类与线程对象. 356
17.3.3 从Thread类继承. 357
17.4 线程同步. 359
17.4.1 线程锁. 359
17.4.2 信号量. 361
17.5 生产者—消费者问题与queue模块. 364
17.6 小结. 366
17.7 实战与练习. 366
第18章 GUI库:tkinter 368
18.1 tkinter简介. 368
18.2 编写个tkinter程序. 368
18.3 布局. 370
18.3.1 pack布局. 370
18.3.2 place布局. 376
18.3.3 grid布局. 377
18.4 控件. 378
18.4.1 Label控件和Button控件. 378
18.4.2 Entry控件与Text控件. 380
18.4.3 Radiobutton控件. 382
18.4.4 Checkbutton控件. 383
18.4.5 Scale 控件. 384
18.4.6 Listbox控件. 386
18.5 向窗口添加菜单. 387
18.6 对话框. 389
18.7 小结. 390
18.8 实战与练习. 390
第19章 GUI库:PyQt5 391
19.1 PyQt5简介. 391
19.2 安装PyQt5 392
19.2.1 PyQt5开发环境搭建. 392
19.2.2 配置QTDesigner(可视化开发). 392
19.2.3 配置PyUIC 395
19.3 编写个PyQt5程序. 397
19.4 窗口的基本功能. 398
19.4.1 设置窗口图标. 398
19.4.2 显示提示框. 398
19.4.3 关闭窗口. 399
19.4.4 消息盒子. 400
19.4.5 窗口居中. 401
19.5 布局. 402
19.5.1 布局. 402
19.5.2 盒布局. 403
19.5.3 网格布局. 405
19.6 控件. 406
19.6.1 QPushButton控件. 406
19.6.2 QLineEdit控件. 408
19.6.3 QCheckBox控件. 409
19.6.4 QSlider控件. 410
19.6.5 QProgressBar控件. 411
19.6.6 QPixmap控件. 413
19.6.7 QComboBox控件. 414
19.6.8 QCalendarWidget控件. 415
19.7 菜单. 416
19.8 小结. 418
19.9 实战与练习. 418
第20章 测试. 419
20.1 先测试后编码. 419
20.1.1 为代码划定边界. 420
20.1.2 测试的步骤. 421
20.2 测试工具. 421
20.2.1 doctest 421
20.2.2 unittest 423
20.3 检查源代码. 424
20.3.1 PyLint 425
20.3.2 Flake8 426
20.4 性能分析. 428
20.5 小结. 429
20.6 实战与练习. 429
第三篇 Python Web开发
第21章 Python Web框架:Flask 433
21.1 Flask基础知识. 434
21.1.1 使用8行代码搞定Web应用. 434
21.1.2 静态路由和动态路由. 435
21.1.3 获取HTTP请求数据. 438
21.1.4 Response与Cookie 439
21.1.5 会话. 441
21.1.6 静态文件和重定向. 443
21.2 Jinja2模板. 443
21.2.1 个基于Jinja2模板的Web应用. 444
21.2.2 在Jinja2模板中使用复杂数据. 445
21.2.3 在Jinja2模板中的过滤器. 447
21.2.4 条件控制. 448
21.2.5 循环控制. 450
21.2.6 宏操作. 452
21.2.7 include指令. 455
21.2.8 模板继承. 457
21.2.9 使用flask-bootstrap模块集成twitter Bootstrap 458
21.2.10 自定义错误页面. 460
21.3 Web表单与Flask-WTF扩展. 461
21.3.1 表单类. 462
21.3.2 简单的表单组件. 464
21.3.3 单选和多选组件. 467
21.3.4 表单校验器. 469
21.3.5 获取和设置表单组件中的数据. 472
21.4 小结. 473
21.5 实战与练习. 474
第22章 Python Web框架:Django 475
22.1 Django开发环境搭建. 475
22.2 Django基础知识. 476
22.2.1 建立个Django工程. 476
22.2.2 Django工程结构分析. 477
22.2.3 远程访问与端口号. 477
22.2.4 用PyCharm建立Django工程. 478
22.2.5 添加路由. 480
22.2.6 在MyCharm中指定IP和端口号. 482
22.2.7 处理HTTP请求. 482
22.2.8 Response与Cookie 484
22.2.9 读写Session 485
22.2.10 用户登录. 487
22.2.11 静态文件. 488
22.3 Django模板. 490
22.3.1 编写个基于Django模板的应用. 490
22.3.2 条件控制标签. 492
22.3.3 循环控制标签. 493
22.3.4 过滤器. 494
22.4 小结. 496
22.5 实战与练习. 496
第四篇 Python科学计算与数据分析
第23章 科学计算库:NumPy 499
23.1 NumPy开发环境搭建. 499
23.2 个NumPy程序. 500
23.3 NumPy数组. 501
23.3.1 创建多维数组. 501
23.3.2 获取数组值和数组的分片. 502
23.3.3 改变数组的维度. 502
23.3.4 水平组合数组. 503
23.3.5 垂直数组组合. 505
23.3.6 水平分隔数组. 505
23.3.7 垂直分隔数组. 507
23.3.8 将数组转换为Python列表. 508
23.4 NumPy常用函数. 509
23.4.1 存取NumPy数组. 509
23.4.2 读写CSV文件. 510
23.4.3 成交量加权平均价格. 511
23.4.4 数组的值、小值和取值范围. 512
23.4.5 计算数组的中位数和方差. 513
23.4.6 计算两只股票的相关性. 514
23.5 小结. 515
23.6 实战与练习. 515
第24章 数据可视化库:Matplotlib 516
24.1 Matplotlib开发环境搭建. 516
24.2 基础知识. 517
24.2.1 个Matplotlib程序. 517
24.2.2 绘制正弦曲线和余弦曲线. 518
24.2.3 绘制随机点. 519
24.2.4 绘制柱状图. 520
24.2.5 绘制直方图与盒状图. 521
24.2.6 绘制饼图. 523
24.3 定制颜色和样式. 524
24.3.1 定制曲线的颜色. 524
24.3.2 定制离散点的样式. 525
24.3.3 定制柱状图颜色. 526
24.3.4 定制饼图颜色. 526
24.3.5 定制曲线类型. 527
24.3.6 定制柱状图的填充模式. 528
24.4 注释. 529
24.4.1 在坐标系上显示标题. 529
24.4.2 使用LaTex格式的标题. 529
24.4.3 为X轴和Y轴添加注释. 530
24.4.4 在坐标系指定位置放置注释. 531
24.4.5 为文本注释添加Box 532
24.5 小结. 532
24.6 实战与练习. 533
第25章 数据分析库:Pandas 534
25.1 Pandas开发环境搭建. 534
25.2 样本数据集. 534
25.3 Pandas基础知识. 535
25.3.1 数据集的装载与基础操作. 535
25.3.2 查看数据集中的列. 536
25.3.3 查看数据集的行. 537
25.3.4 查看数据集单元格中的数据. 538
25.3.5 对数据集进行分组统计. 539
25.3.6 可视化统计数据. 540
25.4 Pandas数据类型. 541
25.4.1 创建Series 541
25.4.2 创建DataFrame 542
25.4.3 Series的基本操作. 543
25.4.4 Series的方法. 544
25.4.5 Series的条件过滤. 545
25.4.6 DataFrame的条件过滤. 546
25.5 小结. 547
25.6 实战与练习. 548
第五篇 Python Web爬虫技术
第26章 网络爬虫与Beautiful Soup 551
26.1 网络爬虫基础. 551
26.1.1 爬虫分类. 552
26.1.2 编写第1个网络爬虫. 552
26.1.3 保存抓取的数据. 555
26.1.4 从百度抓取海量比基尼美女图片. 557
26.2 HTML分析库:Beautiful Soup 560
26.2.1 如何使用Beautiful Soup 560
26.2.2 Tag对象的name和string属性. 562
26.2.3 读写标签属性. 563
26.2.4 用Beautiful Soup分析首页的HTML代码. 564
26.2.5 通过回调函数过滤标签. 565
26.3 支持下载队列的多线程网络爬虫. 566
26.4 小结. 568
26.5 实战与练习. 568
第27章 网络爬虫框架:Scrapy 570
27.1 Scrapy基础知识. 570
27.1.1 Scrapy简介. 570
27.1.2 Scrapy安装. 571
27.1.3 Scrapy Shell抓取Web资源. 571
27.1.4 XPath入门. 573
27.2 用Scrapy编写网络爬虫. 574
27.2.1 创建和使用Scrapy工程. 574
27.2.2 在PyCharm中使用Scrapy 575
27.2.3 使用Scrapy抓取数据并通过XPath指定解析规则. 576
27.2.4 将抓取到的数据保存为多种格式的文件. 577
27.3 小结. 578
27.4 实战与练习. 578
第六篇 Python项目实战
第28章 Web项目实战:基于 Flask的美团网. 581
28.1 项目概述. 581
28.1.1 项目效果演示. 581
28.1.2 项目工程结构. 582
28.2 美团网核心功能实现. 583
28.2.1 设计服务API 583
28.2.2 用Ajax技术与服务端交互. 584
28.3 Python与微信支付. 585
28.3.1 微信支付要准备的数据以及支付流程. 585
28.3.2 编写支付核心类WXPay 586
28.4 小结. 588
第29章 Web项目实战:基于Django的58同城. 589
29.1 项目效果演示. 589
29.2 操作MySQL数据库. 590
29.3 账号. 590
29.3.1 用户注册. 591
29.3.2 用户登录. 592
29.4 招聘页面. 594
29.5 二手车页面. 595
29.6 小结. 597
第30章 网络爬虫实战:天气预报服务API 598
30.1 项目效果演示. 598
30.2 建立MySQL数据库. 599
30.3 抓取天气预报数据. 599
30.4 编写天气预报服务API 600
30.5 实现Web版天气预报查询客户端. 601
30.6 小结. 601
第31章 爬虫项目实战:胸罩销售数据分析. 602
31.1 项目效果演示. 602
31.2 天猫胸罩销售数据. 604
31.2.1 天猫胸罩销售数据分析. 604
31.2.2 抓取天猫胸罩销售数据. 605
31.2.3 抓取胸罩商品列表. 605
31.2.4 将抓取的销售数据保存到SQLite数据库中. 606
31.3 胸罩销售数据. 607
31.3.1 胸罩销售数据分析. 607
31.3.2 抓取胸罩销售数据. 608
31.4 数据清洗. 609
31.5 数据分析与可视化. 611
31.5.1 用SQL语句分析胸罩(按罩杯尺寸)的销售比例. 611
31.5.2 用Pandas和Matplotlib对胸罩销售比例进行可视化分析. 612
31.5.3 按上胸围分析胸罩的销售比例. 613
31.5.4 罩杯和上胸围综合数据可视化分析. 614
31.5.5 统计哪一种颜色的胸罩卖得好. 615
31.5.6 用盒状图与直方图表示罩杯与上胸围分布. 617
31.6 小结. 618
第32章 GUI项目实战:动态修改域名指向的IP 619
32.1 搭建开发环境. 619
32.2 项目效果演示. 619
32.3 获取公网IP 620
32.4 定时更新公网IP 621
32.5 更新域名对应的IP 622
32.6 小结. 623
第33章 游戏项目实战:俄罗斯方块. 624
33.1 搭建开发环境. 624
33.2 项目效果演示. 624
33.3 用户注册. 625
33.4 用户登录. 626
33.5 游戏界面绘制和渲染. 628
33.6 用按键控制游戏. 629
33.7 播放背景音乐. 630
33.8 用户积分. 631
33.9 小结. 632
目前,Python语言的编程应用如火如荼,甚至很多小学都开设了Python语言课程。究其原因,很大程度上是受深度学习的影响。2016年谷歌子公司DeepMind开发的围棋人工智能程序AlphaGo战胜世界围棋冠军李世石以来,科技界一直处于亢奋状态,因为AlphaGo的胜利不仅能证明人工智能程序终于战胜了对人类有挑战的游戏——围棋,而且预示着人工智能具有无限可能。AlphaGo背后的功臣就是近几年越来越火的深度学习,即让人工智能程序通过算法和数据模拟人脑的神经元,从而让人工智能在某些方面达到或超越人类的认知。而深度学习在近几年发展如此迅速,除了硬件性能大幅度提高、数据大量积累,与Python语言也有非常大的关系。Python语言简单易用,运行效率较高,而且拥有众多的深度学习与数据分析程序库,已经成为深度学习的编程语言。
Python语言不仅仅是深度学习的专利,还是一个非常强大的、完备的编程语言,几乎能实现各种类型的应用。例如,通过Flask或Django可以实现任意复杂的Web应用;通过tkinter和PyQt5可以实现跨平台的桌面应用;通过NumPy、Matplotlib、Pandas等程序库可以进行科学计算、数据分析以及数据可视化;通过Beautiful Soup、Scrapy等程序库可以实现强大的网络爬虫。Python语言还有大量第三方的程序库,几乎包含了人们需要的所有功能,所以有很多人将Python看作全栈语言,因为Python语言什么都能做。
由于Python语言涉及的领域很多,学习资料过于分散。因此,我觉得很有必要编写一本全面介绍Python语言在各个主要领域应用与实战的书,并在书中分享我对Python语言以及相关技术的理解和经验,帮助同行和刚开始学习的读者快速掌握Python语言基础知识,还可以利用Python语言编写各种实际的应用。希望本书能起到抛砖引玉的作用,使读者对Python语言及相关技术产生浓厚的兴趣,并将Python语言作为自己的职业生涯中的一项技能。
本书使用了的Python3编写,并在书中探讨了Python3中几乎所有的核心技术。本书分为六篇,共33章,涵盖了Python的基础知识、Python的高级技术、Web开发、数据分析、数据可视化、桌面应用、网络爬虫等常用技术,并在后一篇提供了大量的实战项目以巩固前面所学的知识。此外,本书还提供了超过40小时的同步视频课程,读者可以利用这些视频课程更直观地学习本书的知识。
限于篇幅,本书无法涉及Python语言相关技术的所有方面,只能尽自己所能,与大家分享尽可能多的知识和经验,相信通过对本书的学习,读者可以拥有进一步深度学习的能力,成为Python高手只是时间问题。
后,希望本书能为我国的Python语言以及相关技术的普及、为广大从业者提供有价值的实践经验和快速上手贡献绵薄之力。
作 者
第1章
初识Python
Python是一种跨平台的,面向对象的程序设计语言。本章将简单介绍Python的应用领域,以及学好Python语言的方法,并且还会一步步教读者搭建Python开发环境,毕竟强大的开发工具才是生产力。本章的主要目的是让读者对Python语言有一个整体的了解,然后再一点点深入Python语言的各种技术,后达到完全掌握Python语言的目的。
通过阅读本章,您可以:
q 了解Python语言
q 了解Python的应用领域
q 了解如何学好Python语言
q 了解如何使用Python API文档
q 掌握如何搭建Python开发环境
q 掌握如何使用IDE开发Python程序
q 掌握Python程序的编写方法
q 掌握如何调试Python程序
1.1 Python简介
Python是一种高级的面向对象编程语言。使用Python语言编写的程序是跨平台的,从客户端到服务端,再到Web端,以及移动端,都有Python的身影。Python就是一种全栈编程语言。
1.1.1 什么是Python
Python是一种面向对象的解释型计算机程序设计语言,由荷兰人吉多·范罗苏姆(Guido van Rossum)于1989年发明,个公开发行版发行于1991年。目前Python的发行版是Python 3.6。
Python是纯粹的自由软件,源代码和解释器都遵循 GPL(General Public License)协议。Python语法简洁清晰,特色之一是强制用空白符(white space)作为语句缩进。
Python具有丰富和强大的库。它常被称为胶水语言,能够把用其他语言制作的各种模块(尤其是C/C )很轻松地集成在一起。常见的一种应用场景是,使用Python快速生成程序的原型(有时甚至是程序的终界面),然后对其中有特别要求的部分,用更合适的编程语言改写,例如3D游戏中的图形渲染模块,性能要求特别高,就可以用C/C 重写,然后封装为Python可以调用的扩展类库。需要注意的是,在使用扩展类库时需要考虑平台问题,某些库不提供跨平台的实现。
尽管Python源代码文件(.py)可以直接使用python命令执行,但实际上Python并不是直接解释Python源代码,而是先将Python源代码编译生成Python Byte Code(Python字节码,字节码文件的扩展名一般是.pyc),然后再由Python Virtual Machine(Python虚拟机,可以简称为PVM)来执行Python Byte Code。也就是说,这里说Python是一种解释型语言,指的是解释Python Byte Code,而不是Python源代码。这种机制的基本思想与Java和.NET是一致的。
尽管Python也有自己的虚拟机,但Python的虚拟机与Java或.NET的虚拟机不同的是,Python的虚拟机是一种更高级的虚拟机。这里的高级并不是通常意义上的高级,不是说Python的虚拟机比Java或.NET的功能更强大,而是说与Java 或.NET相比,Python的虚拟机距离真实机器的距离更远。或者可以这么说,Python的虚拟机是一种抽象层次更高的虚拟机。Python语言程序代码的编译和运行过程如图1-1所示。
图1-1 Python语言程序代码的编译和运行过程
1.1.2 Python的应用领域
Python是一种跨平台编程语言,理论上,Python可以运行在任何操作系统平台上。目前常用的操作系统平台是Windows、Mac OS X和Linux。毫无疑问,这三个平台都会成为Python的主战场。
Python的简单易学、众多第三方程序库,以及运行速度快等特性让Python的应用领域异常广泛。Python的应用领域主要有以下几个方面。
q Linux/UNIX运维
q 命令行程序开发
q GUI程序开发(PyQt、Kivy等)
q Web程序开发(Django等框架)
q 移动App开发(PyQt、Kivy等)
q 服务端程序开发(基于Socket等协议)
q 网络爬虫(为搜索引擎、深度学习等领域提供数据源)
q 数据分析
q 深度学习
q 科学计算
尽管这里没有列出Python的所有应用领域,但这些列出的领域就已经包含了绝大多数开发场景。用过Mac OS X或Linux的读者会发现,在这两个操作系统中,已经内置了Python开发环境,也就 是说,Python程序可以在Mac OS X和Linux上直接运行。所以很多运维工程师都习惯使用Python来 完成很多自动化操作。而且Python在操作网络、文本方面尤为突出。Google搜索引擎的个版本就是用Python写的。现在超级火热的深度学习也离不开Python,而且Python已经成为深度学习的语言。因此,从各个角度来看,无论是学生、程序员,还是数据分析师,或是科学家,都离不开Python。Python俨然已经成为编程语言领域的世界语。
1.1.3 如何学好Python
如何学好Python语言,是所有初学者需要共同面对的问题,其实每种编程语言的学习方法都大同小异。下面是给初学者的几点建议。
q 大体了解一下Python是一种怎样的编程语言,以及主要的应用领域。说白了,就是要了解Python能做什么,擅长做什么。对Python语言有一个宏观的认识。
q 搭建开发环境,不管三七二十一,先弄出一个Hello World再说(可以复制现有的代码)。这样会给自己带来继续学习下去的信心。我们可以设想,学了一个星期,如果连一行代码都写不出来,继续学下去的兴趣还会剩多少呢?
q 不要深究设计模式,这些东西是给那些有多年经验的程序员准备的,而且设计模式也不是用来学的,更不是用来记的,是依靠自己的多年经验和实践得出来的。这就像学英语,只管说就好了,管他什么语法,说多了,英语自然就纯正了。所以在一开始写程序时,只管写就好了,让设计模式见鬼去吧!
q 模仿书中的例子代码,一定要自己亲手写代码。当然,一开始为了看运行结果,可以将书中的例子直接复制过来,但一定要完全自己写一遍,代码可以与书中的例子不同,只要实现同样的功能即可。
q 在编写代码的过程中,不需要对Python语言的语法死记硬背,如果某些语法实在记不住,就把这些语法写在卡片上,或干脆放到有道云笔记上,以便随时查看,写多了自然就记住了。
q 初学者不需要大量阅读Python的书籍,也不需要在网上查阅过多的技术资料,因为在自己的功力还没有达到一定火候时,摄入太多的信息会分散自己的精力,可能会适得其反。用一句武林中的话说就是:走火入魔。因此,对于初学者来说,应充分利用本书给出的代码多做练习,当学会了本书给出的各种知识和技巧后,就可以随心所欲地摄取任何自己想获得的知识。
q 读者应充分利用随书赠送的Python视频课程,这套视频课程是与本书同步的。书与视频的差别就是书只能给出一个结果,而视频不仅可以给出结果,还可以详细演示操作过程,这对于初学者尤为重要。
q 在模仿书中例子编写代码的过程中,可能对有些代码没有理解透彻,这并不要紧,读者应仔细阅读本书的相关内容,反复观看随书赠送的Python视频课程,以便领悟其中的奥秘。如果实在领悟不了,也可以到极客起源IT问答社区(https://geekori.com)去提问,会有很多人回答你提出的问题。
q 本书配有大量练习题,读者可以通过这些练习题更好地掌握书和视频中的知识点,而且这些练习题不是生硬地给出,而是通过“过关斩将”“测能力”等形式给出(这些功能需要依托欧瑞科技旗下“极客题库”小程序实现)。读者可以通过这些功能以闯关的方式完成自己的学习任务,并对自己的知识点掌握情况了如指掌。
q 经常总结是一个好习惯,这个习惯对于程序员来说尤其重要。读者可以经常把自己的学习心得,以及经常需要查阅的内容发布到博客(如)上,这样不仅可以提高自己的技术能力,还可以提高自己的语言表达能力。
q 经常回答同行提出的技术问题也是一种提高技术能力的方式,而且更有效。如果你没有能力回答任何技术问题,或只能回答不到10%的技术问题,那么你还是个小白。如果能回答超过30%的技术问题,那么说明你已经至少达到了程序员的中级水平,如果这个比例是50%,那么恭喜你已经成为该领域的高手。如果提高到80%,会毫无悬念地成为该领域的专家。另外,欧瑞科技旗下的极客起源IT问答社区()包含了李宁老师大量学员和读者提出的各种问题,各位读者也可以试试自己到底属于哪个层次。另外,在中提问、回答问题以及撰写博客,都会获得可观的积分,可以换取更多的学习资源。
q 大量阅读源代码。如果前面的方法读者做得都很好,那么相信读者的技术水平已经有了一个质的飞跃,剩下来的工作就是更进一步地提高自己的技术能力。阅读各种开源项目的源代码是一个非常好的方式。另外,要注意,阅读源代码不是目的,目的是要理解这些源代码背后的原理。当然,终的目的是自己可以实现一个类似的功能。读者可以到获取各种类型的Python源代码。
1.1.4 Python API文档
API的全称是Application Programming Interface,即应用程序编程接口。Python官网(https://www.python.org)提供了完整的Python API文档供使用者查阅。这些API文档包括Python语言中所有元素的定义和使用方法(如类、接口、Lambda表达式等),以及所有Library(程序库)的定义和使用方法。不过要注意一点,这些API文档并不是用来学习的,而是当作字典使用的。如果忘记哪个API如何使用,可以利用这些文档进行查找。
目前Python的主流版本分为Python 3.x和Python 2.x。很多操作系统内置的是Python 2.x,因为这一版本的代码积累太大,历史包袱太重,因此很多系统仍然运行在Python 2.x下。不过Python 3.x无论在性能上,还是在语法上,以及在Library上,都有了更大的飞跃,是未来的趋势。所以本书将以Python 3.x为主来介绍Python的各种开发技术。
读者可以访问https://www.python.org/doc进入Python的文档首页,如图1-2所示。
图1-2 Python API文档首页
在Python API文档首页有Python 3.x Docs和Python 2.x Docs两个按钮,单击这两个按钮可以分别进入Python 3.x API文档页面和Python 2.x文档页面。由于本书主要关注Python 3.x,所以现在单击Python 3.x Docs按钮进入Python 3.x API文档页面。
进入文档页面后,默认显示版本的Python API文档,如图1-3所示。目前版本是 Python 3.6.2。在文档页面左上角和左下角是两个完全一样的下拉列表框,可以选择其他Python版本的文档。另外,在文档页面左上角的Download部分可以下载离线Python API文档。
图1-3 Python 3.6.2 API文档页面
在文档页面有多个不同的文档,例如,训练文档(Tutorial)、Library文档(Library Reference)、语法文档(Language Reference)等。读者可以根据需要进入相应的文档。例如,要查阅Python标准库API的使用,可以进入Library Reference页面,会看到如图1-4所示的文档内容。
图1-4 Python标准库API文档
1.2 搭建Python开发环境
“工欲善其事,必先利其器。”在学习Python语言之前,必须先搭建好Python开发环境。Python程序可以直接使用记事本开发,也可以使用IDE(integrated development environment,集成开发环境)开发。不过在大多数项目中,都会使用IDE进行开发。因为IDE支持代码高亮、智能提示、可视化等功能,通过这些功能,可以让开发效率大大提升。因此,本节除了介绍如何通过记事本开发Python程序外,还会介绍如何安装和使用Python IDE。目前有非常多的Python IDE可供选择,本书会介绍两个Python IDE:一个是Eclipse(一个通用的IDE)插件PyDev,另一个是PyCharm。这两个IDE都是跨平台的。读者可以根据自己的喜好决定使用哪个Python IDE。
1.2.1 安装官方的Python运行环境
不管用什么工具开发Python程序,都必须安装Python的运行环境。由于Python是跨平台的,所以在安装之前,先要确定在哪一个操作系统平台上安装,目前常用的是Windows、Mac OS X和Linux三大平台。由于目前使用Windows的人数多,所以本书主要以Windows为主介绍Python运行环境的搭建与程序的开发。
可以直接在Python的官网下载相应操作系统平台的Python安装包:
https://www.python.org/downloads
进入下载页面,浏览器会根据不同的操作系统显示不同的Python安装包下载链接。如果读者使用的是Windows平台,会显示如图1-5所示的Python下载页面。
图1-5 Windows平台的Python下载页面
如果使用的是Mac OS X平台,会显示如图1-6所示的Python下载页面。
图1-6 Mac OS X平台的Python下载页面
不管是哪个操作系统平台的下载页面,都会出现Download Python 3.6.2和Download Python 2.7.13两个按钮(随着时间的推移,可能版本号略有不同)。由于本书使用Python 3讲解,所以单击Download Python 3.6.2按钮即可。如果是Windows平台,下载的是exe安装程序,如果是Mac OS X平台,下载的是pkg文件,这是Mac OS X上的安装程序,直接安装即可。
现在主要来介绍在Windows平台如何安装Python运行环境。首先运行下载的exe文件,会显示如图1-7所示的Python安装界面。建议选中界面下方的Add Python 3.6 to PATH复选框,这样安装程序就会自动将Python的路径加到PATH环境变量中。
在图1-7所示的界面中出现两个安装选项:Install Now和Customize installation,一般单击Install Now即可。单击该选项后,会开始安装Python。图1-8所示是显示安装进度的界面。读者只需要耐心等待Python安装完即可。
图1-7 Windows版Python安装程序初始界面
图1-8 Python安装进度
安装完后,会出现如图1-9所示的安装成功界面。
图1-9 Python安装成功界面
1.2.2 配置PATH环境变量
在安装完Python运行环境后,可以测试一下Python运行环境,如果在安装Python的过程中忘记选中Add Python 3.6 to PATH复选框,那么默认情况下,Python安装程序是不会将Python安装目录添加到PATH环境变量的。这样一来,就无法在Windows命令行工具中的任何目录执行python命令,必须进入Python的安装目录才可以使用python命令。
为了更方便地执行python命令,建议将Python安装目录添加到PATH环境变量中。在Windows平台配置PATH环境变量的步骤如下。
(1)回到Windows的桌面,右击“计算机”,在弹出的快捷菜单中选择“属性”菜单项,会显示如图1-10所示的“系统”窗口。
图1-10 “系统”窗口
(2)单击“系统”窗口左侧的“高级系统设置”,会弹出如图1-11所示的“系统属性”窗口。
(3)单击“系统属性”窗口下方的“环境变量(N)…”按钮,会弹出如图1-12所示的“环境变量”窗口。
图1-11 “系统属性”窗口 图1-12 “环境变量”窗口
(4)在“环境变量”窗口有两个列表,上面的列表是为Windows当前登录用户设置环境变量,在这里设置的环境变量只对当前登录用户有效。下面的列表是对所有用户设置的环境变量,也就是说这些变量对所有的用户都有效。在哪里设置PATH环境变量都可以,本书在上面的列表中设置了PATH环境变量。如果在列表中没有PATH环境变量,单击“新建(N)…”按钮添加一个新的PATH环境变量。如果已经有了PATH环境变量,双击PATH,就会弹出如图1-13所示的“编辑用户变量”对话框。
图1-13 “编辑用户变量”对话框
(5)需要在“变量值(V)”文本框中添加Python的安装目录,多个路径之间要用分号(;)分隔。那么怎么找到Python的安装路径呢?实际上,在图1-7所示安装界面的Install Now按钮下方就是Python的默认安装路径,这个路径可以修改,不过一般保持默认设置即可。如果仍然使用Python的默认安装路径,那么需要在PATH环境变量的后添加如下路径:
C:UsersAdministratorAppDataLocalProgramsPythonPython36-32
进入该路径,会显示如图1-14所示的目录内容。很显然,要使用的就是目录中的python.exe文件。
图1-14 Python安装目录
(6)打开Windows命令行工具,执行python –version命令,如果输出如图1-15所示的内容,则说明Python已经安装成功了。
图1-15 测试Python运行环境
1.2.3 安装Anaconda Python开发环境
开发一个完整的Python应用,仅使用Python本身提供的模块是远远不够的,因此,需要使用大量第三方的模块。在发布Python应用时安装这些第三方模块是一件令人头痛的事,不过有了Anaconda,让这件事轻松不少。Anaconda是一个集成的Python运行环境。除了包含Python本身的运行环境外,还集成了很多第三方模块,如本书后面介绍的NumPy、Pandas、Flask等模块都集成在Anaconda中,也就是说,只要安装了Anaconda,这些模块都不需要安装了。
Anaconda的安装相当简单,首先进入Anaconda的下载页面,地址如下:
https://www.anaconda.com/download
Anaconda的下载页面也会根据用户当前使用的操作系统自动切换到相应的Anaconda安装包。Anaconda是跨平台的,支持Windows、Mac OS X和Linux。不管是哪个操作系统平台的安装包,下载直接安装即可。
Anaconda的安装包分为Python 3.x和Python 2.x两个版本。由于目前Python 3.x版是Python 3.6,而Python 2.x版是Python 2.7,所以习惯上称这两个版本为Python 3.6版和Python 2.7版。由于本书使用的是Python 3.6,所以建议下载Python 3.6版的Anaconda。下载界面如图1-16所示。下载完后,直接安装即可。安装完后,如果未设置Python的PATH环境变量,可以按上一节介绍的方式进行设置。
图1-16 Anaconda的下载页面
1.2.4 下载和安装JDK
可能很多读者会感到奇怪,明明学的是Python,为什么要安装JDK(Java Development Kit,Java开发包)呢?这是因为本书介绍的两个Python IDE都是用Java开发的,所以需要安装JDK才能使用这两个Python IDE。
Java的JDK也称Java SE(以前称J2SE),是Sun公司的产品,由于Sun公司已经被Oracle公司收购,因此,JDK可以在Oracle公司的官方网站http://www.oracle.com下载。
注意:在Java6发布之后,J2SE、J2EE和J2ME正式更名,将名称中的2去掉,更名后分别称为Java SE、Java EE和Java ME。
下面以JDK8为例介绍下载和安装JDK的方法。具体步骤如下:
(1)虽然可以在Oracle公司官网寻找JDK的下载链接,但很不好找。因此,可以通过百度(https://www.baidu.com)或谷歌(https://www.google.com)搜索引擎进行搜索,在搜索框中输入jdk download,个搜索项就是JDK的下载地址。进入JDK的下载页面,如图1-17所示。
图1-17 JDK下载页面
(2)在JDK下载页面选择列表上方的Accept License Agreement选项,然后根据自己使用的操作系统选择合适的版本。例如,如果使用的是64位的Windows,应该选择后一项Windows x64。Windows版的JDK安装程序是一个exe文件,直接单击安装即可。
(3)运行JDK安装程序,会看到如图1-18所示的安装对话框。
图1-18 JDK安装对话框
(4)单击“下一步(N)”按钮,会弹出如图1-19所示的JDK“定制安装”对话框。
(5) JDK默认的安装目录是C:Program FilesJavajdk1.8.0_144,不过这个安装目录中包含Program Files,其中含有空格,对于这种带空格的路径,引用时需要加双引号,比较麻烦。可以单击“更改(C)…”按钮修改JDK默认的安装路径,单击该按钮,会弹出如图1-20所示的“更改文件夹”对话框。在“文件夹名”文本框中输入C:Javajdk8。然后单击“确定”按钮关闭“更改文件夹”对话框。
图1-19 JDK的“定制安装”对话框 图1-20 “更改文件夹”对话框
(6)关闭“更改文件夹”对话框,在“定制安装”对话框中单击“下一步(N)”按钮,会开始安装JDK。现在读者只需等待即可。在安装的过程中会弹出如图1-21所示的“目标文件夹”对话框,要求指定JRE(Java Runtime Environment,Java运行环境)的安装路径。JRE是JDK的子集。JRE只包含运行Java的环境,不包含编译Java源代码的环境,JRE一般用于发布Java程序(因为JRE体积较小)。可以将JRE放到C:JavaJRE8目录中,修改路径的方式与修改JDK安装路径的方式相同。
(7)单击“下一步(N)”按钮,开始安装JDK和JRE。等待一段时间后,如果出现如图1-22所示的对话框,说明JDK已经安装成功了。
图1-21 “目标文件夹”对话框 图1-22 JDK安装完成对话框
(8)读者可以使用1.2.2节介绍的方式将C:JavaJDK8bin路径加到PATH环境变量中,这样在任何目录都可以使用javac.exe命令编译Java程序,使用java.exe命令运行Java程序。
(9)运行Windows命令行工具,执行java -version命令,如果输出如图1-23所示的内容,表示JDK已经安装成功了。
图1-23 测试JDK是否安装成功
1.2.5 下载和安装Eclipse
Eclipse是目前非常流行的一款IDE,采用插件方式提供各种功能。初主要用于开发Java应用,但目前几乎所有的编程语言都提供了Eclipse插件,因此,Eclipse目前支持绝大多数编程语言。开发Python程序可以使用PyDev插件,不过为了使用这个插件,需要先安装Eclipse。
Eclipse的安装分为在线和离线两种模式。在线安装一开始需要下载一个较小的安装包(大概40~50MB),运行安装包后,会要求用户选择要安装的具体Eclipse版本。不过并不建议采用这种方式安装Eclipse,因为在安装的过程中会访问谷歌等网站,其中有一些网站在国内无法访问或速度很慢。所以强烈推荐采用离线方式安装Eclipse。
离线方式首先需要下载Eclipse的完整安装包。安装Eclipse的步骤如下。
(1)进入如下Url指向的Eclipse下载页面:
http://www.eclipse.org/downloads/eclipse-packages
(2)Eclipse的下载页面如图1-24所示。在这个下载页面中,出现了很多Eclipse下载项,这些下载项基本都是Eclipse应用于不同领域的版本。可以选择Eclipse IDE for Java Developers,这个版本非常洁净,只可以开发Java SE应用。对于Windows用户来说,选择右侧32bit或64bit版本。
图1-24 Eclipse的下载页面
假设选择的是64bit版本,会进入该版本的下载页面。在页面的会出现如图1-25所示的DOWNLOAD按钮。
图1-25 64bit版Eclipse for Windows下载页面
不过好先不要单击DOWNLOAD按钮,因为默认的下载镜像可能下载速度会很慢。可以单击Select Another Mirror链接选择其他的下载镜像。单击该链接,下面会展现出更多的下载镜像,如图1-26所示。
(3)可以选择一个下载比较快的镜像链接,如“大连东软信息学院”,然后单击链接下载即可。一般单击下载镜像链接后,会进入如图1-27所示的Eclipse自动下载页面,过几秒钟会自动下载Eclipse的离线安装包(180MB左右)。如果没有自动下载,可单击页面上方的click here链接下载Eclipse离线安装包。
图 1-26 更多的下载镜像链接 图1-27 Eclipse自动下载页面
(4)下载完Eclipse离线安装包(是一个zip压缩文件),直接解压即可。然后运行根目录中的eclipse.exe文件就可以启动Eclipse。
1.2.6 Python IDE(PyDev)安装
PyDev可以采用在线方式进行安装。
(1)进入Eclipse后,选择Help→Install New Software菜单项,会弹出如图1-28所示的Install对话框。
图1-28 Install对话框
(2)单击Install对话框右上角的Add按钮,会弹出Add Repository对话框,在Name文本框中输入PyDev,在Location文本框中输入http://pydev.org/updates,如图1-29所示。然后单击OK按钮关闭Add Repository对话框。
(3)关闭Add Repository对话框后,会从http://pydev.org/updates下载要更新的插件信息,因此,这时要保证网络畅通。更新完插件信息后,会在Install对话框的列表中显示如图1-30所示的插件信息。
图1-29 Add Repository对话框 图1-30 Install对话框
(4)选中所有的列表项,单击Next按钮完成安装。如果Eclipse没有安装过PyDev插件,Next按钮是可以单击的,如果Eclipse已经安装了PyDev插件,则Next按钮不可用。
(5)如果Next按钮可用,单击Next按钮,进入下一个窗口(Install Details),如图1-31所示。继续单击Next按钮,进入下一个窗口。
图1-31 Install Details窗口
(6)单击Next按钮后,会显示如图1-32所示的Review Licenses窗口,选择右下角的I accept the terms of the license agreements单选按钮,然后单击Finish按钮开始安装PyDev。
图1-32 Review Licenses窗口
(7)在安装的过程中,Eclipse的下方会出现如图1-33所示的Progress进度条。
图1-33 安装PyDev的进度
(8)在安装的过程中,可能会弹出如图1-34所示的对话框。询问用户是否信任PyDev开发者的证书。选中列表中的复选框,单击Accept selected按钮,会继续安装PyDev插件。
(9)在安装的过程中,如果出现如图1-35所示或类似的对话框,单击Install anyway按钮继续安装。
图1-34 Selection Needed对话框 图1-35 Security Warning对话框
(10)安装时间可能较长,请读者耐心等待,安装完后,会要求重启Eclipse,按要求操作即可。
1.2.7 配置Python IDE(PyDev)开发环境
PyDev并不包含Python运行环境,所以在使用PyDev之前,要将PyDev在1.2.1节安装的Python运行环境与PyDev关联。
(1)在Eclipse中选择Window→Preferences菜单项,然后从弹出的Preferences对话框左侧的列表树中选择PyDev→Interpreters→Python Interpreter节点,在右侧会显示相应的设置界面,如图1-36所示。
图1-36 Preferences对话框
(2)单击Preferences对话框右上侧的Quick Auto-Config按钮,会自动检测Python运行环境,检测成功后,单击Apply and Close按钮关闭Preferences对话框。
1.2.8 测试Python IDE(PyDev)开发环境
到现在为止,PyDev已经安装完成了,本节来测试一下PyDev开发环境。首先需要建立一个Python工程。在Eclipse中选择File→New→PyDev Project菜单项,会弹出如图1-37所示的PyDev Project对话框。在Project name文本框中输入MyFirstPython,在Grammar Version列表框中选择3.6,然后选 择下面的Create ‘src’ folder and add it to the PYTHONPATH选项,后单击Finish按钮创建Python 工程。
创建完MyFirstPython工程后,在工程中有一个src目录,选择该目录,在右击弹出的快捷菜单中选择New→File菜单项,在弹出的New File对话框下方的File name文本框中输入Test.py,然后单击Finish按钮,会在src目录建立一个Test.py文件,如图1-38所示。
图1-37 PyDev Project对话框 图1-38 MyFirstPython工程的目录结构
双击Test.py文件,会在右侧出现代码编辑区域。输入如下的代码:
print(“Hello World”)
选中Test.py,在右击弹出的快捷菜单中选择Run As→Python Run菜单项,这时会运行Test.py,并在Eclipse的Console视图输出如图1-39所示的结果。
如果第二次及以后运行Test.py程序,直接单击如图1-40所示Eclipse工具条偏左侧的按钮即可。
图1-39 在Console视图输出结果 图1-40 Python程序运行按钮
1.2.9 安装PyCharm
PyCharm是一个专门用于开发Python程序的IDE,由JetBrains公司开发,这个公司开发出了很多非常流行的IDE,如WebStorm、Intellj IDEA等,其中Android Studio(开发Android App的IDE)就是基于Intellj IDEA社区版开发的。
PyCharm有两个版本:社区版和专业版。社区版是免费的,但功能有限,不过使用PyCharm编写本书的案例足够了。
可以到下面的PyCharm官网下载PyCharm的安装文件:
https://www.jetbrains.com/pycharm
进入PyCharm下载页面后,将页面垂直滚动条滑动到中下部,会看到如图1-41所示的PyCharm专业版和社区版的下载按钮。
图1-41 下载PyCharm
PyCharm下载页面会根据用户当前使用的操作系统自动切换到相应的安装文件,Windows是exe文件,Mac OS X是dmg文件,Linux是tar.gz文件。只需要单击右侧的DOWNLOAD按钮即可下载相应操作系统平台的安装程序。
下载完PyCharm后即可运行PyCharm,第1次运行PyCharm,会显示如图1-42所示的欢迎界面。单击Create New Project按钮即可建立Python工程。
图1-42 PyCharm的欢迎界面
1.2.10 配置PyCharm
单击图1-42所示PyCharm欢迎界面中的Create New Project按钮会显示New Project窗口,该窗口是用来创建Python工程的。在Location文本框中输入Python工程的名字,如果要选择不同的Python运行环境,可以单击Project Interpreter,会在New Project窗口下方显示如图1-43所示的Python运行环境选择界面。
图1-43 New Project窗口
如果已经配置好了PyCharm中的Python运行环境,从Interpreter列表中选择一个Python运行环境即可。如果还没有对PyCharm进行配置,需要单击Interpreter列表框右侧的按钮,然后在弹出的菜单中选择Add Local菜单项,此时会弹出如图1-44所示的Add Local Python Interpreter窗口。
选择左侧列表中的Virtualenv Environment,单击右侧Interpreter列表框右侧的省略号按钮,会弹出一个Select Python Interpreter窗口,如图1-45所示。在该窗口中选择Anaconda或其他Python解释器,然后单击OK按钮关闭该窗口。
图1-44 Add Local Python Interpreter窗口
图1-45 Select Python Interpreter窗口
接下来回到图1-43所示的New Project窗口,在Interpreter列表中选择刚才指定的Python运行环境,后单击Create按钮创建Python工程。一个空的Python工程如图1-46所示。
Python源代码文件可以放在Python工程的任何位置,通常会将Python源代码文件放在src目录中,然后选择src目录,在右击弹出的快捷菜单中选择New→Python File菜单项创建一个Python文件(这里是Test.py),如图1-47所示。
图1-46 空的Python工程 图1-47 创建Test.py文件
次运行Python程序可以选择Test.py文件,然后在右击弹出的快捷菜单中选择Run Test菜单项会运行Test.py脚本文件,以后再运行,可以直接单击MyPython主界面右上角的绿色箭头按钮。现在为Test.py文件输入一行简单的代码,如print(‘hello world ‘),然后运行Test.py脚本文件,会得到如图1-48所示的输出结果。如果按前面的步骤进行,并得到这个输出结果,就说明PyCharm已经安装成功。
图1-48 在PyCharm中运行Python脚本文件
1.2.11 Python中的REPL环境
Python有如下三种运行方式。
q 直接通过python命令运行
q 在Python IDE中运行
q 在Python的REPL环境中运行
本节将介绍如何在REPL环境中运行Python程序,这里的REPL是Read-Eval-Print Loop的缩写,是一个简单的交互式编程环境,也可以将Python REPL环境称为Python控制台。为了统一,本书后面的章节都称Python REPL为Python控制台。
只需要在Windows命令行工具中执行python命令,即可进入REPL环境。在命令提示符(>>>)后输入print(“hello world”),按Enter键,就会在REPL环境中输出hello world,如图1-49所示。
如果在Windows下,按Ctrl Z键退出REPL环境;如果在Mac OS X下,按Ctrl D键退出REPL环境。
图1-49 Python的REPL环境
1.3 个Python程序
【例1.1】 下面编写本书的个Python程序。这个程序定义了两个整数类型的变量n和m,并将两个变量相加,后调用print函数输出这两个变量的和。
实例位置:PythonSamplessrcchapter1demo1.01.py
(1)可以使用任何一个文本编辑器、Eclipse或PyCharm创建demo.py文件,并输入下面的Python代码。
n = 20
m = 30
print(“n m =”,n m)
建议使用Eclipse或PyCharm来创建demo.dy文件,因为这样做可以直接在IDE中执行Python程序,并不需要像命令行方式运行Python程序那样在文本编辑器和Windows命令行工具之间来回切换。
(2)运行Python程序。
如果想在Windows命令行工具中运行demo1.py,可以在命令行工具中进入demo1.py所在的目录,然后执行下面的命令运行demo1.py:
python demo1.py
在命令行工具中运行demo1.py的输出结果如图1-50所示。
如果想在Eclipse中运行demo1.1.py,可以参照1.2.8节的方法操作,在Eclipse的Console视图中输出的结果如图1-51所示。
图1-50 Windows命令行工具中输出的结果 图1-51 在Eclipse的Console视图中输出的结果
1.4 调试Python程序
在开发复杂的Python程序时,如果出现bug(也就是程序中出现的错误),就需要对程序进行调试,以便找出bug对应的代码行。调试程序的方法很多,例如,可以使用print函数在程序的不同位置输出相应的信息,以便缩小bug出现的范围。不过这种方法太原始了,现在普遍使用的方法是通过调试器一步步跟踪代码行,这种方式可以非常方便地找到bug所在的位置。
由于PyDev是Eclipse插件,所以调试Python程序可以使用与调试Java类似的方式(PyCharm的调试方法类似)。Eclipse提供了调试接口,后台调用了各种编程语言的调试器。在调试Python代码时会调用Python的调试器。
用Python调试器调试Python代码的步骤如下。
1.设置断点
设置断点是调试程序的过程中必不可少的一步。Python调试器每次遇到断点时会将当前线程挂起,也就是暂停当前程序的运行。
可以在Python编辑器中显示代码行号的位置双击添加或删除当前行的断点,或者在当前行号的位置右击,会显示如图1-52所示的快捷菜单。在菜单中选择Add Breakpoint菜单项,会在当前代码行添加断点。也可以选择Disable Breakpoint菜单项,禁用当前行的断点。如果当前行已经有断点了,菜单中会出现Remove Breakpoint菜单项,选择该菜单项,会删除当前行的断点。
添加断点后的Python编辑器如图1-53所示。其中第2行设置了一个断点。
图1-52 在Python编辑器中添加断点 图1-53 Python编辑器设置断点后的效果
2.以调试方式运行Python程序
在Eclipse中运行分为两种方式:Release和Debug,也就是发行和调试。如果只是观察程序的执行效果,可以选择Release方式,如果要调试程序,就需要使用Debug方式。
Debug按钮在Eclipse工具栏左侧,如图1-54所示(有一个小爬虫的按钮,在Release按钮的左侧)。
图1-54 Debug按钮
现在单击Debug按钮,就会运行Python程序,如果Python程序没有设置任何断点,Debug和Release方式运行的效果是一样的,都会输出运行结果。不过用Debug方式运行程序,Eclipse会进入Debug透视图(Perspective),这里的透视图就是Eclipse中将多个相关视图以一定位置和尺寸放到一起,便于开展工作。Debug透视图则是将与调试相关的视图放到一起,便于调试。
如果Python程序中有断点,当程序执行到断点处,就会暂停程序,并且在断点行用绿色背景展示,如图1-55所示。
3.观察调试信息
调试的主要目的是将程序中的数据展现出来,也就是说,调试调的就是程序中的数据。因此,通过Python调试器,可以用多种方式观察Python程序中数据的变化。例如,由于n = 20在m = 30前面,所以在m = 30处中断后,n = 20肯定是已经执行了,所以可以将鼠标放到n = 20语句上,这时会在弹出窗口中显示变量n的数据类型和当前的值,如图1-56所示。
图1-55 程序停留在断点行的效果 图1-56 显示变量的数据类型和当前的值
在Variables视图中也可以观察变量值的变化情况,如图1-57所示。
图1-57 Variables视图
4.跟踪调试程序
调试的另一个重要功能是可以一步步跟踪程序,也就是step into(单独跳入)和step over(单步跳过)。其中,step into可以跟踪进函数内部,step over并不会跟踪进函数内部。这两个功能可以通过单击左上侧的两个按钮实现,如图1-58所示。
图1-58 step into和step over按钮
现在单击step over按钮,会发现Python代码区域m = 30代码行执行了,并且绿色背景跑到下一行,如图1-59所示。
图1-59 用step over跟踪代码行
1.5 小结
本章简单介绍了Python语言的历史和Python语言的应用领域。另外,还介绍了Windows系统平台中搭建Python开发环境和IDE(PyDev和PyCharm)的方法,以及编写Python程序的简单步骤,后介绍了如何在Eclipse中调试Python程序。通过本章的学习,读者应该能够了解什么是Python语言,以及能用Python语言来做什么和如何学好Python语言。本章的重点是Python开发环境的搭建,读者应该熟练掌握。
1.6 实战与练习
本章练习题,除了配有答案(源代码)外,还会在赠送的视频课程中讲解。
1.尝试修改例1.1,使程序输出n * m的值。
答案位置:PythonSamplessrcchapter1practicesolution1.1.py
2.尝试编写Python程序,分别用“*、 、-、/”四个四则运算符将两行字符串包围起来,并在Eclipse的Console视图中输出如图1-60所示的结果。
答案位置:PythonSamplessrcchapter1practicesolution1.2.py
图1-60 Python程序运行结果
第2章
Python语言基础
有很多人在学习Python语言时为了图快、贪多,一上来就学什么网络、多线程、并发、网络爬虫,甚至是深度学习。其实学这些技术都没问题,有旺盛的求知欲总是好的。不过这些技术的基础,却是Python语言中被认为简单,一看就知道,不看也能猜出个八九不离十的基础知识。这些人认为这些基础的东西,差不多就行,还是学些炫酷的东西更过瘾。其实学习Python语言就像踮着脚尖够东西,差1mm你也够不着。所以还是老老实实打一下Python语言的基础,这样在以后学习Python高级技术的过程中才会游刃有余。
通过阅读本章,您可以:
q 了解如何声明变量
q 了解如何导入Python模块
q 掌握如何在二、八、十和十六进制之间互相转换
q 掌握如何格式化数字
q 掌握单行注释和多行注释
q 了解单引号字符串和双引号字符串
q 了解拼接字符串
q 掌握长字符串
2.1 Python程序中的基本要素
尽管Python语言与Java语言一样,是一种面向对象语言,但Python语言相对Java语言来说,代码编写比较自由。Python语言并不像Java语言那样需要定义一个main方法作为入口点。Python程序的代码可以像批处理文件一样从上到下按顺序编写,这也是为什么Python语言适合运维的原因,因为在运维中,就直接把Python语言当成一种批处理语言了。尽管Python语言的代码自由度更大,但这并不等于Python语言的代码可以随便编写,Python语言的代码仍然需要一定的结构,例如,对于有一定复杂度的Python程序,不可能只使用Python语言中内置的功能,还需要引用很多外部的API,这些API在Python语言中称为模块,因此,Python语言中必不可少的部分就是引用模块。除此之外,在Python代码中会包含大量声明变量的代码。所以引用模块和声明变量,几乎每一个Python程序都要用到。在本节深入讲解Python语言基础知识之前,会首先介绍一下如何在Python语言中导入模块和声明变量。
2.1.1 导入Python模块
在Python代码中导入模块需要使用import语句,语法结构如下:
import module_name
引用模块中函数的语法如下:
module_name.function_name
如果在Python程序中大量使用模块中的某些函数,那么每次在调用函数时都要加上“模块名”显得有些麻烦,所以在这种情况下,可以使用from…import…语句将模块中的函数直接暴露出来。该语句的语法结构如下:
from module_name import function_name
如果要想导入模块中的所有函数,可以将function_name替换成星号(*),这样就可以直接使用该模块中的所有函数。
from module_name import *
另外,import和from…import…语句可以写在Python代码中的任何位置,但一定要在引用相应模块函数之前执行import或from…import…语句,否则调用函数时会抛出异常。
【例2.1】 下面的代码使用import和from…import…语句分别引用了math模块和math模块中的sqrt函数。如果要调用math模块中的其他函数,必须在函数名前加上math.前缀,但可以直接调用sqrt函数计算数值的平方根。
实例位置:PythonSamplessrcchapter2demo2.01.py
print(“import和from…import…演示”)
# 导入math模块
import math
print(math.floor(20.6))
# 导入math模块中的sqrt函数
from math import sqrt
print(sqrt(12))
# 导入math模块中的所有函数
from math import *
print(sin(3.14/2))
程序运行结果如图2-1所示。
图2-1 导入math模块并调用math模块中的函数
2.1.2 声明变量
变量(variable)是Python语言中一个非常重要的概念。变量的主要作用就是为Python程序中的某个值起一个名字。类似于“张三”“李四”“王二麻子”一样的人名,便于记忆。
在Python语言中,声明变量的同时需要为其赋值,毕竟不代表任何值的变量毫无意义,Python语言中也不允许有这样的变量。
声明一个变量也非常简单,语法结构如下:
variable_name = variable_value
等号(=)左侧是变量名,右侧是变量值,赋完值后,Python编译器会自动识别变量的类型。
注意:变量不能随便起名,必须符合一定的规则。变量名通常包含字母、数字和下画线(_),变量名不能以数字开头。例如,value315是一个合法的变量名,而315value是错误的变量名。
【例2.2】 下面的代码声明了多个变量,这些变量的数据类型包括整数、字符串、布尔和浮点数。后输出这些变量的值。
实例位置:PythonSamplessrcchapter2demo2.02.py
x = 20 # 声明整数类型变量
y = 40 # 声明整数类型变量
s = “I love python” # 声明字符串类型变量
flag = True # 声明布尔类型变量
u = 30.4 # 声明浮点类型变量
print(flag) # 输出flag变量的值
print(x y) # 输出x和y的和
print(s) # 输出s变量的值
print(u) # 输出u变量的值
程序运行结果如图2-2所示。
图2-2 声明变量和输出变量的值
2.1.3 清空Python控制台
执行Python命令会进入Python控制台。在Python控制台中可以用交互的方式执行Python语句。也就是执行一行Python语句,会立刻返回执行结果。
当Python控制台输入过多的Python语句时,有时需要将这些已经输入的语句和执行结果清空,并重新开始输入Python语句。例如,图2-3就是一个输入了多条Python语句,并输出相应结果的Python控制台。
图2-3 输入多条Python语句的Python控制台
当然,如果不想看到这些Python语句和输出结果,可以一直按Enter键,直到Python控制台中所有的内容都移到窗口上面为止。不过这样一来,光标还是在Python控制台的下面,而且上面都是Python控制台的命令提示符,非常难看,如图2-4所示。
图2-4 连续按Enter键后的Python控制台
如果用的是Mac OS X系统,在Python控制台中按Ctrl L键就可以直接清空Python控制台。而在Windows中,是没有快捷键用来清空Python控制台的,所以需要编写Python代码来实现清空Python控制台的功能。因此,本节的目的到现在已经很清楚了,本节主要并不是教大家如何清空Python控制台,而是借用清空Python控制台这一操作,利用前面两节介绍的导入模块和声明变量的知识,编写一段Python程序,用来清空Python for Windows控制台。
在Windows下,如果要清空Windows控制台,执行cls命令即可。由于Python控制台是利用Windows控制台实现的,所以cls命令也同样可以清空Python控制台。不过在Python控制台不能直接执行cls命令。在Python控制台要想执行外部命令,需要调用os模块中的system函数。读者可以一行一行在Python控制台输入下面的代码。
import os # 导入os模块
os.system(‘cls’) # 执行cls命令清空Python控制台
执行这两行代码,是把以前在Python控制台中输入的内容都清空了,但在Python控制台的第1行会输出一个0,如图2-5所示。
其实这个0是os.system函数的返回值。Python控制台会输出每一条执行语句的返回值。os.system函数如果成功执行命令,返回0,如果执行命令失败,返回1。不过为了追求完美,现在就把这个0去掉。
图2-5 清空Python控制台
之所以会输出这个0,是因为Python语言的标准输出默认指向的是Python控制台,所以所有的Python语句执行的结果都输出到了Python控制台。现在只要改变Python语言的标准输出,让其指向一个文件,那么os.system函数的执行结果就会直接写到这个文件中,而不是Python控制台。
【例2.3】 本例会编写一个Python程序,用于清空Python控制台。
清空Python控制台不输出0的步骤如下:
(1)导入os模块和sys模块。
(2)使用open函数以可写的方式打开一个文件,本例是out.log。
(3)为了不影响在Python控制台输出其他语句的执行结果,应先将Python默认的标准输出保存到一个变量中,以便以后恢复默认的Python标准输出。使用sys.stdout可以获取Python标准输出的句柄(Handler)。
(4)将Python标准输出指向第2步打开的文件。
(5)使用os.system函数执行cls命令。
(6)恢复Python默认的标准输出。
完整的实现代码如下。读者可以在Python控制台一行行输入这些代码,当执行到os.system(‘cls’)语句时,Python控制台被清空,不会再显示0。
实例位置:PythonSamplessrcchapter2demo2.03.py
import os # 导入os模块
import sys # 导入sys模块
f_handler=open(‘out.log’, ‘w’) # 打开out.log文件
oldstdout = sys.stdout # 保存默认的Python标准输出
sys.stdout=f_handler # 将Python标准输出指向out.log
os.system(‘cls’) # 清空Python控制台
sys.stdout = oldstdout # 恢复Python默认的标准输出
2.2 数字
数字是Python程序中常见的元素。在Python控制台中可以直接输入用于计算的表达式(如1 2 * 3),按Enter键就会输出表达式的计算结果,因此,Python控制台可以作为一个能计算表达式的计算器使用。
在Python语言中,数字分为整数和浮点数。支持基本的四则运算和一些其他的运算操作,并且可以利用一些函数在不同的进制之间进行转换,以及按一定的格式输出数字。本节会就这些知识点一一展开,来深入讲解在Python语言中如何操作数字。
2.2.1 基础知识
Python语言与其他编程语言一样,也支持四则运算(加、减、乘、除),以及圆括号运算符。在Python语言中,数字分为整数和浮点数。整数就是无小数部分的数,浮点数就是有小数部分的数。例如,下面的代码是标准的四则运算表达式。
2 4
4 * 5 20
5.3 / 7
(30 2) * 12
如果要计算两个数的除法,不管分子和分母是整数还是浮点数,使用除法运算符(/)的计算结果都是浮点数。例如,1/2的计算结果是0.5,2/2的计算结果是1.0。要想让Python解释器执行整除操作,可以使用整除运算符,也就是两个斜杠(//)。使用整除运算符后,1 // 2的计算结果是0,2 // 2的计算结果是1。
整除运算符不仅能对整数执行整除操作,也能对浮点数执行整除操作,在执行整除操作时,分子分母只要有一个是浮点数,那么计算结果就是浮点数。例如,1.0 // 2的计算结果是0.0,2.0 // 2的计算结果是1.0。
除了四则运算符外,Python还提供了两个特殊的运算符:%(取余运算符)和**(幂运算符)。取余运算符用于对整数和浮点数执行取余操作。例如,5 % 2的计算结果是1,而5.0 % 2的计算结果是1.0。从这一点可以看出,%和//类似,只要分子分母有一个是浮点数,计算结果就是浮点数。幂运算符用于计算一个数值的幂次方。例如,2 ** 3的计算结果是8,3.2 ** 2的计算结果是10.24。
到现在为止,一共介绍了8个运算符,它们是圆括号((…))、加( )、减(-)、乘(*)、除(/)、整除(//)、取余(%)和幂运算符(**)。其中,减号(-)也可以用于负号(一元运算符),所以现在涉及9个运算符。既然涉及这么多运算符,那么就有一个优先级的问题,也就是说,同一个表达式中包含有多个不同的运算符,需要先计算优先级高的运算符,如果优先级相同,那么就按从左向右的顺序执行。
这9个运算符的优先级顺序如表2-1所示。越靠前优先级越高,同一行的运算符的优先级相同。
表2-1 运算符优先级
【例2.4】 下面的代码演示了Python语言中运算符的使用方法,在编写Python代码时,应该注意运算符的优先级问题。
实例位置:PythonSamplessrcchapter2demo2.04.py
print(2 4) # 运算结果:6
print(126 – 654) # 运算结果:-528
print(6 20 * 4) # 运算结果:86
print((20 54) * 30) # 运算结果:2220
print(1/2) # 运算结果:0.5
print(1//2) # 运算结果:0
print(3/2) # 运算结果:1.5
print(3//2) # 运算结果:1
print(4**3) # 运算结果:64
print(3 5 * -3 ** 4 – (-5)**2) # 运算结果:-427
# 用变量操作数值
x = 30
y = 50
k = 10.2
print(x y * k) # 运算结果:540.0
程序运行结果如图2-6所示。
图2-6 Python运算符演示结果
2.2.2 大整数
对于有符号32位整数来说,可表示的值是2 147 483 647(2^31 -1),可表示的小值是 -2 147 483 648(-2^31),如果超过这个范围,有符号32位整数就会溢出。不过在Python语言中,可以处理非常大的整数,并不受位数限制。例如,下面表达式的输出结果就超出了32位整数的范围。
print(2 ** 35) # 输出2的35次幂,输出结果是34359738368
再换个更大的数,看看会不会溢出。
print(2**630 * 100000) # 2的630次幂再乘10万
上面这行代码的输出结果如下:
445550841564667501820426914619169074696604346410992180720624269326101090547722401025968047980212050759633038044296328838934443820446820117016861457004122479321483854917994624031530682836582400000
很显然,Python语言仍然可以正确处理2**630 * 100 000的计算结果。因此,在Python语言中使用数字不需要担心溢出,因为Python语言可以处理非常大的数字,这也是为什么很多人使用Python语言进行科学计算和数据分析的主要原因之一。
2.2.3 二进制、八进制和十六进制
Python语言可以表示二进制、八进制和十六进制数。表示这三个进制的数,必须以0开头,然后分别跟着表示不同进制的字母。表示二进制的字母是b,表示八进制的字母是o(这是英文字母中小写的o,不要和数字0搞混了),表示十六进制的字母是x。因此,二进制数的正确写法是0b110011,八进制数的正确写法是0o56432,十六进制数的正确写法是0xF765A。
除了这三种进制外,前面章节一直使用的是十进制。因此,Python语言一共可以表示4种进制:二进制、八进制、十进制和十六进制。Python语言提供了一些函数用于在这4种进制数之间进行转换。
如果是从其他进制转换到十进制,需要使用int函数。该函数有两个参数,含义如下:
q 第1个参数为字符串类型,表示待转换的二进制、八进制或十六进制数。参数值只需要指定带转换的数即可,不需要使用前缀,如二进制直接指定11011,不需要指定0b11011。
q 第2个参数为数值类型,表示第1个参数值的进制。例如,如果要将二进制转换为十进制,第2个参数值就是2。
int函数返回一个数值类型,表示转换后的十进制数。
下面的代码将二进制数110011转换为十进制数,并输出返回结果。
print(int(“110011”,2)) // 输出结果:51
如果要从十进制转换到其他进制,需要分别使用bin、oct和hex函数。bin函数用于将十进制数转换为二进制数,oct函数用于将十进制数转换为八进制数,hex函数用于将十进制数转换为十六进制数。这三个函数都接收一个参数,就是待转换的十进制数。不过要注意,这三个函数的参数值也可以是二进制数、八进制数和十六进制数,也就是说,这三个函数可以在二进制、八进制、十进制和十六进制之间互转。
下面的代码将十进制数54321转换为十六进制数,并输出转换结果。
print(hex(54321)) # 输出结果:0xd431
【例2.5】 下面的代码演示了Python语言中二进制、八进制、十进制和十六进制数之间的转换。
实例位置:PythonSamplessrcchapter2demo2.05.py
print(0b110011) # 输出二进制数
print(0o123) # 输出八进制数
print(0xF15) # 输出十六进制数
print(bin(12)) # 十进制转二进制,输出结果:0b1100
print(int(“10110”,2)) # 二进制转十进制,输出结果:22
print(int(“0xF35AE”,16)) # 十六进制转十进制,输出结果:996782
print(hex(54321)) # 十进制转十六进制,输出结果:0xd5431
print(bin(0xF012E)) # 十六进制转二进制,输出结果:0b11110000000100101110
print(hex(0b1101101)) # 二进制转十六进制,输出结果:0x6d
print(oct(1234)) # 十进制转八进制,输出结果:0o2322
print(int(“76532”, 8)) # 八进制转十进制,输出结果:32090
程序运行结果如图2-7所示。
2.2.4 数字的格式化输出
在输出数字时,有时需要对其进行格式化。例如,在输出12.34时,只希望保留小数点后1位数字,也就是12.3,或整数位按6位输出,不足前面补0,也就是000012.34。Python语言中提供了format函数用于对数字进行格式化。format函数有两个参数,含义如下:
q 第1个参数为要格式化的数字。
q 第2个参数为格式字符串。
format函数的返回值就是数字格式化后的字符串。
图2-7 进制转换的输出结果
【例2.6】 下面的代码演示了format函数在格式化数字方面的应用。
实例位置:PythonSamplessrcchapter2demo2.06.py
x = 1234.56789
# 小数点后保留两位数,输出结果:’1234.57′
print(format(x, ‘0.2f’))
# 数字在12个字符长度的区域内右对齐,并保留小数点后1位数字,
# 输出结果:’ 1234.6′
print(format(x, ‘>12.1f’))
# 数字在12个字符长度的区域内左对齐,并保留小数点后3位数字,紧接着输出20,
# 输出结果:’1234.568 20′
print(format(x, ‘<12.3f’), 20)
# 数字在12个字符长度的区域内右对齐,并保留小数点后1位数字,数字前面补0,
# 输出结果:’0000001234.6′
print(format(x, ‘0>12.1f’))
# 数字在12个字符长度的区域内左对齐,并保留小数点后1位数字,数字后面补0,
# 输出结果:’1234.6000000′
print(format(x, ‘0<12.1f’))
# 数字在12个字符长度的区域内中心对齐,并保留小数点后2位数字,紧接着输出3,
# 输出结果:’ 1234.57 3′
print(format(x, ‘^12.2f’),3)
# 每千位用逗号(,)分隔,输出结果:1,234.56789
print(format(x, ‘,’))
# 每千位用逗号(,)分隔,并保留小数点后2位数字,输出结果:1,234.57
print(format(x, ‘,.2f’))
# 用科学计数法形式输出数字,输出结果:1.234568e 03
print(format(x, ‘e’))
# 用科学计数法形式输出数字,尾数保留小数点后2位数字,输出结果:1.23E 03
print(format(x, ‘0.2E’))
程序运行结果如图2-8所示。
图2-8 format函数格式化数字后的输出结果
2.3 获取用户输入
要编写一个有实际价值的程序,就需要与用户交互。当然,与用户交互有很多方法。例如,GUI(图形用户接口)就是一种非常好的与用户交互的方式,不过先不讨论GUI的交互方式,本节会采用一种原始,但很有效的方式与用户交互,这就是命令行交互方式。也就是说,用户通过命令行方式输入数据,程序会读取这些数据,并做进一步的处理。
从命令行接收用户的输入数据,需要使用input函数。input函数接收一个字符串类型的参数,作为输入的提示。input函数的返回值就是用户在命令行中录入的值。不管用户录入什么数据,input函数都会以字符串形式返回。如果要获取其他类型的值,如整数、浮点数,需要用相应的函数转换。例如,字符串转换为整数的函数是int,字符串转换为浮点数的函数是float。
【例2.7】 本例要求用户在命令行中输入姓名、年龄和收入。其中年龄是整数,收入是浮点数。输入完这三个值后,会依次在控制台输出这三个值。由于年龄和收入都是数值,所以在获取用户输入值后,需要分别使用int和float函数将input函数的返回值转换为整数和浮点数。如果年龄和收入输入的是非数值,会抛出异常。
实例位置:PythonSamplessrcchapter2demo2.07.py
name = input(“请输入你的名字:”) # 输入姓名,并把输入的结果赋给name变量
age = int(input(“请输入你的年龄:”)) # 输入年龄,并把输入的结果赋给age变量
salary = float(input(“请输入你的收入:”)) # 输入收入,并把输入的结果赋给salary变量
print(“姓名:”, name) # 输出姓名
print(“年龄:”, age) # 输出年龄
print(“收入:”, format(salary, “0.1f”)) # 输出收入
运行程序,分别输入姓名、年龄和收入,按Enter键后,会输出如图2-9所示的内容。
图2-9 使用input函数从命令行输入数据
2.4 函数
在2.2.1节中曾经介绍过使用幂运算符(**)来计算一个数的n次方。事实上,可以用一个函数来代替这个运算符,这个函数就是pow,该函数可以传入两个参数,如果要计算x的y次方,那么pow函数的第1个参数应该是x,第2个参数应该是y。pow函数返回计算结果。例如,下面的代码计算2的6次方。
result = pow(2,6) # 计算结果:64
像上面这行代码使用函数的方式叫作函数调用。函数相当于可以重用的代码段,如果在程序中有多处使用这段代码,就应该将这段代码放到函数中,这样既可以实现代码重用,还会避免代码冗余。可以想象,如果不使用函数,同样的代码出现在程序中的多个地方,一旦要修改这些代码,那简直就是噩梦,需要改很多个地方。
Python语言提供了很多内建的函数以及通过模块提供的更多的函数,这些函数可以很大程度上实现代码复用,例如,abs函数用于获取数值的值,round函数用于浮点数取整(四舍五入),cmath模块的sin函数用于计算弧度的正弦。
【例2.8】 本例演示了如何使用Python语言内建的函数以及模块提供的函数实现代码复用。
实例位置:PythonSamplessrcchapter2demo2.08.py
from cmath import sin # 导入cmath模块中的sin函数
print(pow(2,5)) # 运行结果:32
print(abs(-12)) # 运行结果:12
print(sin(3.14 / 2)) # 运行结果:(0.9999996829318346 0j)
print(round(3.6)) # 运行结果:4
print(round(3.4)) # 运行结果:3
程序运行结果如图2-10所示。
图2-10 调用Python语言中的函数
2.5 注释
任何编程语言都有注释的功能。所谓注释,就是用一段文本描述代码的作用、代码的作者或是其他需要描述的东西。注释在程序编译时被忽略,也就是说,注释只在源代码中体现,编译生成的二进制文件中是没有注释的。
在Python语言中,注释分为单行注释和多行注释。单行注释用井号(#)开头,多行注释用三个引号(单引号或双引号)括起来。如果使用单行注释,井号后面的所有内容在编译程序时都会被忽略,如果使用多行注释,被引号括起来的内容在编译程序时都会被忽略。
在使用某些Python IDE时,默认会用ASCII编码格式保存源代码文件,这时如果源代码文件中含有中文,在运行Python程序时就会出错,这时需要使用注释标注当前源代码文件保存的编码格式。
用utf-8编码格式保存源代码文件:
# coding=utf-8
用gbk编码格式保存源代码文件:
# coding=gbk
建议使用utf-8编码格式保存源代码文件,因为utf-8不仅仅能保存中文,还可以保存其他国家的文字,如韩文、日文。所以utf-8编码格式使用更普遍。
【例2.9】 本例演示了Python语言中单行注释和多行注释的用法。
实例位置:PythonSamplessrcchapter2demo2.09.py
# coding=utf-8 当前Python源代码文件以utf-8编码格式保存
“”” 多行注释(用双引号括起来)
作者:李宁
地点:earth
“””
# 用于计算2的4次幂 单行注释
print(2 ** 4)
”’ 多行注释(用单引号括起来)
这段代码用于计算一个表达式的值
(1 2) * 20
”’
print((1 2) * 20)
2.6 字符串基础
字符串是Python语言中另外一个重要数据类型,在Python语言中,字符串可以使用双引号(”)或单引号(’)将值括起来。例如,下面都是合法的字符串值。
s1 = “hello world”
s2 = ‘I love you.’
字符串也同样可以被print函数输出到控制台,这种用法在前面已经多次使用过了。
print(“hello world”)
在前面的章节尽管已经多次使用了字符串,但只涉及字符串的一些简单用法,如定义字符串变量、输出字符串等。本节将介绍字符串的更多用法。
2.6.1 单引号字符串和转义符
字符串与数字一样,都是值,可以直接使用,在Python控制台中直接输入字符串,如”Hello World”,会按原样输出该字符串,只不过用单引号括了起来。
>>> “Hello World”
‘Hello World’
那么用双引号和单引号括起来的字符串有什么区别呢?其实没有任何区别。只不过在输出单引号或双引号时方便而已。例如,在Python控制台输入’Let’s go!’,会抛出如下的错误。
>>> ‘Let’s go!’
File “”, line 1
‘Let’s go!’
^
SyntaxError: invalid syntax
这是因为Python解释器无法判断字符串中间的单引号是正常的字符,还是多余的单引号,所以会抛出语法错误异常。要输出单引号的方法很多,其中之一就是使用双引号将字符串括起来。
>>> “Let’s go!”
“Let’s go!”
现在输出单引号是解决了,但如何输出双引号呢?其实很简单,只需要用单引号将字符串括起来即可。
>>> ‘我们应该在文本框中输入”Python”‘
‘我们应该在文本框中输入”Python”‘
现在输出单引号和输出双引号都解决了,那么如何同时输出单引号和双引号呢?对于这种需求,就要使用本节要介绍的另外一个知识点:转义符。Python语言中的转义符是反斜杠()。转义符的功能是告诉Python解释器反斜杠后面的是字符串中的一部分,而不是用于将字符串括起来的单引号或双引号。所以如果字符串中同时包含单引号和双引号,那么转义符是必需的。
print(‘Let’s go!. “一起走天涯”‘) # Let’s go!. “一起走天涯”
在上面这行代码中,单引号和双引号都是用的转义符,其实在这个例子中,由于字符串是由单引号括起来的,所以如果里面包含双引号,是不需要对双引号使用转义符的。
【例2.10】 本例演示了Python语言中单引号和双引号的用法,以及转义符在字符串中的应用。
实例位置:PythonSamplessrcchapter2demo2.10.py
# 使用单引号的字符串,输出结果:Hello World
print(‘Hello World’)
# 使用双引号的字符串,输出结果:Hello World
print(“Hello World”)
# 字符串中包含单引号,输出结果:Let’s go!
print(“Let’s go!”)
# 字符串中包含双引号,输出结果:”一起走天涯”
print(‘”一起走天涯”‘)
# 字符串中同时包含单引号和双引号,其中单引号使用了转义符,输出结果:Let’s go! “一人我饮酒醉”
print(‘Let’s go! “一人我饮酒醉” ‘)
程序运行结果如图2-11所示。
图2-11 输出单引号和双引号字符串
2.6.2 拼接字符串
在输出字符串时,有时字符串会很长,在这种情况下,可以将字符串写成多个部分,然后拼接到一起。可以尝试下面的一种写法。
>>> ‘Hello’ ‘world’
‘Helloworld’
这种写法是将两个字符串挨着写到一起,字符串中间可以有0到n个空格。现在看看这种方式能否将两个字符串变量的值组合到一起。
>>> x = ‘hello’
>>> y = ‘world’
>>> x y
File “”, line 1
x y
^
SyntaxError: invalid syntax
可以看到,如果是两个字符串类型的变量紧挨着写在一起,Python解释器就会认为是语法错误,所以这种方式实际上并不是字符串的拼接,只是一种写法而已,而且这种写法必须是两个或多个字符串值写在一起,而且不能出现变量,否则Python解释器就会认为是语法错误。
如果要连接字符串,要用加号( ),也就是字符串的加法运算。
>>> x = ‘Hello ‘
>>> x ‘World’
‘Hello World’
【例2.11】 本例演示了字符串拼接的方法。
实例位置:PythonSamplessrcchapter2demo2.11.py
# 将字符串写到一起输出,运行结果:helloworld世界你好
print(“hello” “world” “世界你好”)
x = “hello” # 声明字符串变量x
y = “world” # 声明字符串变量y
#print(x y) # 抛出异常,变量不能直接写到一起
print(x y) # 字符串拼接,要使用加号( ),运行结果:helloworld
程序运行结果如图2-12所示。
图2-12 字符串拼接
2.6.3 保持字符串的原汁原味
在2.6.1节讲过转义符()的应用,其实转义符不光能输出单引号和双引号,还能控制字符串的格式。例如,使用“n”表示换行,如果在字符串中含有“n”,那么“n”后的所有字符都会被移到下一行。
>>> print(‘HellonWorld’)
Hello
World
如果要混合输出数字和字符串,并且换行,可以先用str函数将数字转换为字符串,然后在需要换行的地方加上“n”。
>>> print(str(1234) “n” str(4321))
1234
4321
不过有的时候,不希望Python解析器转义特殊字符,希望按原始字符串输出,这时需要使用repr函数。
>>> print(repr(“HellonWorld”))
‘HellonWorld’
使用repr函数输出的字符串,会使用一对单引号括起来。
其实如果只想输出“n”或其他类似的转义符,也可以使用两个反斜杠输出“”,这样“”后面的n就会被认为是普通的字符。
>>> print(“Hello\nWorld”)
HellonWorld
除了前面介绍的repr和转义符外,在字符串前面加r也可以原样输出字符串。
>>> print(r”HellonWorld”)
HellonWorld
现在总结一下,如果让一个字符串按原始内容输出(不进行转义),有如下三种方法:
q repr函数
q 转义符()
q 在字符串前面加r
【例2.12】 本例演示了str函数和repr函数的用法。
实例位置:PythonSamplessrcchapter2demo2.12.py
# 输出带“n”的字符串,运行结果:
# world>
print(“”)
# 用str函数将1234转换为数字,运行结果:1234
print(str(1234))
# 抛出异常,len函数不能直接获取数字的长度
#print(len(1234))
# 将1234转换为字符串后,获取字符串长度,运行结果:4
print(len(str(1234)))
# 运行结果:
# world>
print(str(“”))
# 运行结果:13
print(len(str(“”)))
# 运行结果:”
print(repr(“”))
# 运行结果:16
print(len(repr(“”)))
# 使用转义符输出“”,输出的字符串不会用单引号括起来,运行结果:
print(“”)
# 运行结果:14
print(len(“”))
# 在字符串前面加“r”,保持字符串原始格式输出,运行结果:
print(r””)
# 运行结果:14
print(len(r””))
程序运行结果如图2-13所示。
图2-13 输出原始字符串
可以看到,使用repr函数输出的“”字符串被一对单引号括了起来,而且字符串长度是16。而使用str函数输出同样的字符串,长度是13。在str函数输出的字符串中,“n”算一个字符,长度为1,而用repr函数输出的字符串中,“n”是两个字符,长度为2。再加上一对单引号,所以长度是16。
2.6.4 长字符串
在2.5节讲了使用三个单引号或双引号括起来的文本会成为多行注释,其实如果将这样的字符串使用print函数输出,或赋给一个变量,就会成为一个长字符串。在长字符串中会保留原始的格式。
print(“””Hello # 长字符串,会按原始格式输出
World”””);
如果使用长字符串表示一个字符串,中间可以混合使用双引号和单引号,而不需要加转义符。
print(“””Hell”o” # 长字符串,中间混合使用双引号和单引号
W’o’rld”””
对于普通字符串来说,同样可以用多行来表示。只需要在每一行后面加转义符(),这样一来,换行符本身就“转义”了,会被自动忽略,所以后都会变成一行字符串。
print(“Hellon # 输出一行字符串
World”)
【例2.13】 本例演示了长字符串的用法。
实例位置:PythonSamplessrcchapter2demo2.13.py
print(”’I # 使用3个单引号定义长字符串
‘love’
“Python”
”’
)
s = “””Hello # 使用双引号定义长字符串
World
世界
你好
“””
print(s) # 输出长字符串
print(“Hello # 每行字符串在回车符之前用转义符,就可以将字符串写成多行
World”)
程序运行结果如图2-14所示。
图2-14 输出长字符串
2.7 小结
本章介绍了一些Python语言的基础知识。其实核心知识点只有两个:数字和字符串。数字主要涉及一些进制之间的转换以及格式化输出数字。这些都是数字的基本操作。本章介绍的字符串操作非常基础,但很重要。尤其是转义符的应用,读者要认真阅读本章的内容。实际上,Python语言中的字符串操作非常复杂,功能也十分强大,所涉及的内容远不止本章介绍的这些知识点。在后面会用专门的一章详细介绍字符串的操作。
2.8 实战与练习
本章练习题,除了配有答案(源代码)外,还会在赠送的视频课程中讲解。
1. 请将下面的数值转成另外三种进制,并使用print函数输出转换结果。例如,如果数值是十进制,需要转换成二、八、十六进制;如果是十六进制,需要转换为二、八、十进制。
(1)12345
(2)0xF98A
(3)0b1100010110
答案位置:PythonSamplessrcchapter2practicesolution2.1.py
2. 现在有一个变量x,值为5423.5346,使用format函数对该变量进行格式化,并使用print函数输出如下的5个格式化后的值。
(1)保留小数点后3位数字,格式化后的结果:5423.535。
(2)保留小数点后2位数字,让整数和小数部分,以及小数点一共占10位,左侧位数不够补0。格式化后的结果:0005423.53。
(3)保留小数点后2位数字,让整数和小数部分,以及小数点一共占10位,右侧位数不够补0。格式化后的结果:5423.53000。
(4)在第2个格式化结果的基础上,在千分位用逗号(,)分隔,格式化后的结果:005,423.53。
(5)保留小数点后2位数字,让整数和小数部分,以及小数点一共占10位,位数不够前后补0,格式化后的结果:05,423.530。
答案位置:PythonSamplessrcchapter2practicesolution2.2.py
第3章
条件、循环和其他语句
在前面的章节学习了一些Python语言的基础知识,不过到目前为止,这些Python代码都只是从上到下顺序执行的,很像批处理,从条语句一直执行到后一条语句,然后程序退出。但在实际应用中,这样的程序几乎没什么实际的用处。因为有实用价值的程序需要有两个功能:选择和重复执行。其中,“选择”就是根据不同的条件,执行不同的程序分支,这样程序才会有所谓的“智能”,另外,“重复执行”也是程序的一个重要功能,计算机系统之所以完成机械的工作的效率远比人类高,就是因为依靠强大的CPU和GPU不断重复执行程序。
“选择”和“重复执行”在编程语言中称为条件和循环。在Python语言中,条件使用if语句实现,而循环需要使用while和for语句,也就是说,Python语言中有两种循环语句。其实,包括前面讲的顺序结构,以及本章将要介绍的条件和循环,有一个统一的名称,叫作“控制流程”。本章除了要介绍条件和循环语句外,还会讲一些Python语言中有趣的功能,例如,动态执行Python代码。
通过阅读本章,您可以:
q 了解print函数更高级的用法
q 了解序列解包、链式和增量赋值方法
q 了解Python语言中的代码块
q 掌握if条件语句的用法
q 掌握嵌套代码块的用法
q 了解Python语言中常用的运算符
q 掌握断言的使用方法
q 掌握while循环的使用方法
q 掌握for循环的使用方法
q 了解如何使用嵌套循环
q 掌握循环中的else子句的用法
q 掌握动态执行Python代码和Python表达式的方法
3.1 神奇的print函数
相信读者一定对print函数不陌生,因为在前面的章节,几乎每个例子都使用了print函数,这个函数的功能就是在控制台输出文本。不过print在输出文本时还可以进行一些设置,以及输出多参数字符串。
如果为print函数传入多个参数值,那么print函数会将所有的参数值首尾相接输出。
# 输出结果:a b c d e
print(“a”,”b”,”c”,”d”,”e”);
可以看到,上面的这行代码输出了a到e,共5个字母。在Python控制台中输出了“a b c d e”。很明显是将这5个字符首尾相接输出了。不过这些字母之间用空格分隔,这是print函数默认的分隔符,用于分隔输出的多个参数值,这个默认设置是非常有用的。例如,执行下面的代码,会在等号(=)后面加一个空格。
print(“name =”, “Bill”)
print(“age =”, 30)
输出结果如下:
name = Bill
age = 30
其中等号(=)前面的空格是第1个参数值包含的。
print函数会为除了第1个参数值以外的其他参数值前面添加一个空格,这样做,在需要用空格分隔的场景下,就不需要在每一个参数值前面添加空格了。
不过这种默认设置有利有弊,在不需要用空格分隔时,print函数仍然会添加空格。例如,要输出字符串“Apple,Orange,Banana”。其中Apple、Orange和Banana之间用逗号(,)分隔,逗号(,)与英文单词之间没有空格。如果按前面的做法,会有如下的代码输出这行字符串。
print(“Apple”,”,”, “Orange”,”,”,”Banana”)
输出的结果如下:
Apple,Orange,Banana
很明显,逗号(,)前后都有空格。当然,可以将逗号(,)与前面的英文单词合并,但逗号(,)与后面的英文单词之间仍然会有空格。
解决这个问题的方法很多,例如,可以用传统的字符串相加的方式输出字符串“Apple,Orange,Banana”。
print(“Apple” “,” “Orange” “,” “Banana”)
现在要用print函数特有的方法解决这个问题,就是修改默认的多参数值分隔符。在print函数后添加“sep=”,””,就可以将分隔符从空格改成逗号(,)。现在可以直接使用下面的代码输出字符串“Apple,Orange,Banana”。
print(“Apple”, “Orange”,”Banana”, sep=”,”)
输出结果:
Apple,Orange,Banana
print函数输出字符串时,默认会在字符串结尾添加换行符(n),这样每次调用print函数输出字符串,都会另起一行。不过有时希望调用多次print函数都在同一行输出,这时可以在print函数后加上“end=” “”,让后一个输出字符串结尾符变成空格,而不是原来的“n”,当然,也可以将结尾符设成长度为0的字符串,这样多次使用print函数输出的结果就会首尾相接,中间没有任何分隔符。
print(“a”,end=””);
print(“b”,end=””);
print(“c”);
输出结果:
abc
【例3.1】 本例演示了print函数输出多参数值,修改默认多参数值分隔符,以及修改输出字符串结尾字符的方法。
实例位置:PythonSamplessrcchapter3demo3.01.py
# 输出用空格分隔的多参数值
print(“name =”, “Bill”)
# 输出用空格分隔的多参数值
print(“age =”, 30)
# 使用加号( )连接字符串
print(“Apple” “,” “Orange” “,” “Banana”)
# 修改多参数值分隔符为逗号(,),然后输出多参数值
print(“Apple”, “Orange”,”Banana”, sep=”,”)
# 修改多参数值分隔符为“&”,然后输出多参数值
print(“Can”,”you”,”tell”,”me”, “how”, “to”, “get”, “to”,”the”,”nearest”, “tube”, “station”, sep=”&”)
# 修改输出字符串结尾符为空格,这样下一次调用print函数,就会从同一行输出内容了
# 运行结果:Hello world
print(“Hello”, end=” “)
print(“world”)
# 修改输出字符串结尾符为长度为0的字符串,这样下一次调用print函数,输出的内容不仅会在同一行,
# 而且会首尾相接,运行结果:abc
print(“a”,end=””);
print(“b”,end=””);
print(“c”);
程序运行结果如图3-1所示。
图3-1 print函数的用法
3.2 有趣的赋值操作
在很多读者看来,赋值操作是再简单不过了,在前面的章节也多次使用了赋值操作。不过Python语言中的赋值操作要有趣得多。例如,可以同时将多个值赋给多个变量。
>>> x,y,z = 1,2,3
>>> print(x,y,z)
1 2 3
在上面的代码中,将1、2、3分别赋给了x、y、z三个变量,并输出这三个变量的值。使用Python语言中的这个特性可以很容易实现两个变量中值的交换。
>>> x,y = 20,30
>>> x,y = y,x
>>> print(x,y)
30 20
# x,y,z = 1,2 # 抛出异常
# x,y = 1,2,3 # 抛出异常
这种同时将多个值赋给多个变量的操作,等号(=)右侧的值与左侧的变量个数必须相等,否则会抛出异常。
>>> x,y,z = 1,2
Traceback (most recent call last):
File “”, line 1, in
ValueError: not enough values to unpack (expected 3, got 2)
>>> x,y = 1,2,3
Traceback (most recent call last):
File “”, line 1, in
ValueError: too many values to unpack (expected 2)
Python语言的这种特性称为序列解包(sequence unpacking),其实任何一个可迭代(iterable)的对象都支持这一特性。关于迭代对象(列表、集合等)的详细信息会在后面的章节介绍。
Python语言还支持链式赋值(chained assignments)和增量赋值(augmented assignments),链式赋值是指将同一个值连续赋给多个变量。
x = y = 20
增量赋值是指将变量自身增加或减小(负增量)指定值的表达式的简化形式。例如,x = x 2,如果用增量赋值表达式,可以写成x = 2,也就是将等号(=)右侧的x省略,并将加号( )放到等号左侧。
其实前面介绍的二元运算符都支持增量赋值,例如,x = x * 20可以写成x *= 20,x = x % 3可以写成x %= 3。
【例3.2】 本例演示了序列解包、链式赋值和增量赋值的使用方法。
实例位置:PythonSamplessrcchapter3demo3.02.py
x,y,z = 1,2,3 # 使用序列解包方式进行赋值
print(x,y,z)
x,y = y,x # 利用序列解包交换x和y的值
print(x,y)
# x,y,z = 1,2 # 抛出异常
# x,y = 1,2,3 # 抛出异常
x = y = 20 # 使用链式赋值设置x和y
print(x,y)
x *= 2 # 增量赋值
x %= 3 # 增量赋值
print(x)
程序运行结果如图3-2所示。
图3-2 赋值操作的应用
3.3 用缩进创建代码块
代码块并非一种语句,而是在学习条件和循环语句之前必须要掌握的知识。
代码块是在条件为真(true)时执行的一组语句,在代码前放置空格来缩进语句即可创建代码块。
注意:使用tab字符也可以缩进语句形成代码块。Python将一个tab字符解释为到下一个tab字符位置的移动,而一个tab字符为8个空格,不过Python标准推荐使用空格缩进的方式创建代码块,建议使用4个空格缩进的方式创建代码块。
代码块的每行语句应该缩进同样的量。下面的伪代码(并非真正的Python代码)展示了如何用缩进的方式创建代码块。
This is a code line
This is another code line:
This is a block
continuing the same block
the last line of this block
We escaped the inner block
很多编程语言使用特殊单词或字符来表示一个代码块的开始,用另外的单词或字符表示代码块的结束,例如,Pascal语言使用begin表示代码块的开始,使用end表示代码块的结束,而C风格的编程语言(如Java、C#、C 等)使用一对大括号表示代码块的开始和结束。Python语言和这些语言都不一样,Python语言使用冒号(:)表示代码块的开始,代码块中的每一条语句都是缩进的(缩进量相同)。当回退到与块的开始语句同样的缩进量时,就表示当前块已经结束。很多集成开发环境(IDE)会帮助用户轻松把握缩进,因此不必担心缩进量不对导致Python程序无法编译通过。
现在已经了解了如何使用Python语言中的缩进块,在下面几节将详细介绍各种缩进块的应用。
3.4 条件和条件语句
到目前为止,Python语句都是一条一条顺序执行的,在这一节会介绍如何让程序选择是否执行代码块中的语句。
3.4.1 布尔值和布尔变量
在讲条件语句之前,首先应该了解一下布尔(boolean)类型。条件语句(if)需要为其指定布尔值或布尔类型的变量,才能根据条件判断是否要指定代码块中的语句。布尔值只有两个值:True和False,可以将这两个值翻译成“真”和“假”。
现在已经了解了布尔值是用来做什么的,但Python语言会将哪些值看作布尔值呢?其实在Python语言中,每一种类型的值都可以被解释成布尔类型的值。例如,下面的值都会被解释成布尔值中的False。
None 0 “” () [] {}
这些值所涉及的数据类型有一些到现在为止并没有讲过(例如,[]表示长度为0的列表),不过也不用担心,在后面的章节会详细讲解这些数据类型。
如果在条件语句中使用上面的这些值,那么条件语句中的条件都会被解释成False,也就是说,条件代码块中的语句不会被执行。
在Python语言底层,会将布尔值True 看作1,将布尔值False看作0,尽管从表面上看,True和1、False和0是完全不同的两个值,但实际上,它们是相同的。可以在Python控制台验证这一点。
>>> True == 1
True
>>> False == 0
True
>>> True False 20
21
很明显,可以直接将True看成1,将False看成0,也可以直接将True和False当成1和0用,所以True False 20的计算结果是21。
另外,可以用bool函数将其他类型的值转换为布尔类型的值。
>>> bool(“”)
False
>>> bool(“Hello”)
True
>>> bool([])
False
>>> bool([1,2,3])
True
>>> bool(20)
True
>>> bool(”)
False
可以看到,在前面给出的几个会被系统认为是False的值,通过bool函数的转换,会变成真正的布尔值。不过这些值是不能直接和布尔值比较的,例如,不能直接使用“[] == false”,正确的做法是先用bool函数将其转换为布尔值,然后再比较:
bool([]) == false
在前面的代码中使用了“==”运算符,这是逻辑运算符,是二元运算符,需要指定左右两个操作数用于判断两个值是否相等,如果两个操作数相等,运算结果为True,否则为False。这个运算符在后面的章节中会经常用到,当然,还有很多类似的运算符,在讲解条件语句时会一起介绍。
3.4.2 条件语句(if、else和elif)
对于计算机程序来说,要学会的项技能就是“转弯”,也就是根据不同的条件,执行不同的程序分支,这样的程序才有意义。
if语句的作用就是为程序赋予这项“转弯”的技能。使用if语句就需要用到在3.3节介绍的代码块。Python语言要求当if语句的条件满足时要执行的代码块必须缩进(一般是缩进4个空格)。if语句的语法格式如下:
if logic expression: # if代码块开始
statement1
statement2
…
statementn
otherstatement # if代码块结束
其中,logic expression表示逻辑表达式,也就是返回布尔类型值(True或False)的表达式。由于Python语句的各种数据类型都可以用作布尔类型,所以logic expression可以看作普通的表达式。根据代码块的规则,每一个代码块的开始行的结尾要使用冒号(:),如果if代码块结束,退到代码块开始行的缩进量即可。
下面是if语句的基本用法。
n = 3
if n == 3:
print(“n == 3”)
print(“if代码块结束”)
在上面这段代码中,“n == 3”是逻辑表达式,本例中的值为True。而“print(“n == 3”)”是if代码块中的语句,由于“n == 3”的值为True,所以“print(“n == 3”)”会被执行。后一条语句不属于if代码块,所以无论if语句的条件是否为True,这行代码都会被执行。
对于条件语句来说,往往分支不止一个。例如,上面的代码如果变量n的值是4,那么if语句的条件就为False,这时要执行条件为False的分支,就可以使用else子句。
n = 4
if n == 3:
print(“n == 3”)
else:
print(“n等于其他值”)
print(“if代码块结束”)
在上面这段代码中,n等于4,所以if语句的条件为False,因此else代码块中的语句会被执行。if与else都是代码块,所以if语句和else语句后面都要以冒号(:)结尾。
在多分支条件语句,需要使用elif子句设置更多的条件。elif后面跟逻辑表达式,elif也是代码块,所以后面要用冒号(:)结尾。另外,在if语句中,if和else部分只能有一个,而elif部分可以有任意多个。
n = 4
if n == 3:
print(“n == 3”)
elif n == 4:
print(“n == 4”)
elif n == 5:
print(“n == 5”)
else:
print(“n等于其他值”)
print(“if代码块结束”)
【例3.3】 本例通过raw_input函数从控制台输入一个名字,然后通过条件语句判断名字以什么字母开头。
实例位置:PythonSamplessrcchapter3demo3.03.py
from click._compat import raw_input
name = raw_input(“请输入您的名字:”) # 从控制台输入名字
if name.startswith(“B”): # if代码块
print(“名字以B开头”)
elif name.startswith(“F”): # elif代码块
print(“名字以F开头”)
elif name.startswith(“T”): # elif代码块
print(“名字以T开头”)
else: # else代码块
print(“名字以其他字母开头”)
程序运行结果如图3-3所示。
图3-3 条件语句
3.4.3 嵌套代码块
条件语句可以进行嵌套,也就是说,在一个条件代码块中,可以有另外一个条件代码块。包含嵌套代码块B的代码块A可以称为B的父代码块。嵌套代码块仍然需要在父代码块的基础上增加缩进量来放置自己的代码块。下面的例子会演示如何使用嵌套代码块进行逻辑判断。
【例3.4】 本例要求在Python控制台输入一个姓名,然后通过嵌套代码块判断输入的姓名,根据判断结果输出结果。
实例位置:PythonSamplessrcchapter3demo3.04.py
name = input(“你叫什么名字?”) # 从Python控制台输入一个字符串(姓名)
if name.startswith(“Bill”): # 以Bill开头的姓名
if name.endswith(“Gates”): # 以Gates结尾的姓名(嵌套代码块)
print(“欢迎Bill Gates先生”)
elif name.endswith(“Clinton”): # 以Clinton结尾的姓名
print(“欢迎克林顿先生”)
else: # 其他姓名
print(“未知姓名”)
elif name.startswith(“李”): # 以“李”开头的姓名
if name.endswith(“宁”): # 以“宁”结尾的姓名
print(“欢迎李宁老师”)
else: # 其他姓名
print(“未知姓名”)
else: # 其他姓名
print(“未知姓名”)
程序运行结果如图3-4所示。
图3-4 嵌套代码块的输出结果
3.4.4 比较运算符
尽管if语句本身的知识到现在为止已经全部讲完了,不过我们的学习远没有结束。前面给出的if语句的条件都非常简单,但在实际应用中,if语句的条件可能非常复杂,这就需要使用到本节要介绍的比较运算符。
现在先来看一下表3-1列出的Python语言中的比较运算符。
表3-1 Python语言中的比较运算符
在表3-1描述的比较运算符中,涉及对象和容器的概念,目前还没讲这些技术,在本节只需了解Python语言可以通过比较运算符操作对象和容器即可,在后面介绍对象和容器的章节,会详细介绍如何利用相关比较运算符操作对象和容器。
在比较运算符中,常用的就是判断两个值是否相等。例如,a大于b,a等于b。这些运算符包括“==”“”“>=”“<=”和“!=”。
如果比较两个值是否相等,需要使用“==”运算符,也就是两个等号。
>>> “hello” == “hello”
True
>>> “Hello” == “hello”
False
>>> 30 == 10
False
要注意,如果比较两个字符串是否相等,会比较两个字符串中对应的每一个字母,所以“Hello”和“hello”并不相等,也就是说比较运算符是对大小写敏感的。
在使用“==”运算符时一定要注意,不要写成一个等号(=),否则就成赋值运算符了。对于赋值运算符来说,等号(=)左侧必须是一个变量,否则会抛出异常。
>>> “hello” = “hello” # 使用赋值运算符,会抛出异常
File “”, line 1
SyntaxError: can’t assign to literal
>>> s = “hello”
>>> s
‘hello’
对于字符串、数值等类型的值,也可以使用大于(>)、小于(
>>> “hello” > “Hello”
True
>>> 20 > 30
False
>>> s = 40
>>> s <= 30
False
>>> “hello” != “Hello”
True
Python语言在比较字符串时,会按字母ASCII顺序进行比较,例如,比较“hello”和“Hello”的大小。首先会比较’h’和’H’的大小,很明显’h’的ASCII大于’H’的ASCII,所以后面的都不需要比较了,因此,”hello” > “Hello”的结果是True。
如果一个字符串是另一个字符串的前缀,那么比较这两个字符串,Python语言会认为长的字符串更大一些。
>>> “hello” < “hello world”
True
除了比较大小的几个运算符外,还有用来确定两个对象是否相等的运算符,以及判断某个值是否属于一个容器的运算符,尽管现在还没有讲到对象和容器,但这里不妨做一个实验,来看看这些运算符如何使用,以便以后学习对象和容器时,更容易掌握这些运算符。
用于判断两个对象是否相等的运算符是is和is not,这两个运算符看起来和等于运算符(==)差不多,不过用起来却大有玄机。
>>> x = y = [1,2,3]
>>> z = [1,2,3]
>>> x == y
True
>>> x == z
True
>>> x is y
True
>>> x is z
False
>>> x is not z
True
在上面的代码中,使用“==”和is比较x和y时结果完全一样,不过在比较x和z时,就会体现出差异。x == z的结果是True,而x is z的结果却是False。出现这样的结果,原因是“==”运算符比较的是对象的值,x和z的值都是一个列表(也可以将列表看作一个对象),并且列表中的元素个数和值完全一样,所以x == z的结果是True。但is运算符用于判断对象的同一性,也就是说,不仅对象的值要完全一样,而且对象本身还要是同一个对象,很明显,x和y是同一个对象,因为在赋值时,先将一个列表赋给y,然后再将y的值赋给x,所以x和y指向了同一个对象,而z另外赋值了一个列表,所以z和x、y尽管值相同,但并不是指向的同一个对象,因此,x is z的结果就是False。
判断某个值是否属于一个容器,要使用in和not in运算符。下面的代码首先定义一个列表变量x,然后判断变量y和一些值是否属于x。
>>> x = [1,2,3,4,5] # 定义一个列表变量
>>> y = 3
>>> 1 in x
True
>>> y in x
True
>>> 20 in x
False
>>> 20 not in x
True
in和not in运算符也可以用于判断一个字符串是否包含另外一个字符串,也就是说,可以将字符串看作字符或子字符串的容器。
>>> s = “hello world”
>>> ‘e’ in s
True
>>> “e” in s
True
>>> “x” in s
False
>>> “x” not in s
True
>>> “world” in s
True
如果遇到需要将多个逻辑表达式组合在一起的情况,需要用到逻辑与(and)、逻辑或(or)和逻辑非(not)。逻辑与的运算规则是只有x and y中的x和y都为True时,运算结果才是True,否则为False。逻辑或的运算规则是只有x or y中的x和y都为False时,运算结果才是False,否则都为True。逻辑非的运算规则是not x中,x为True,运算结果为False;x为False,运算结果为True。
>>> 20 < 30 and 40 < 50
True
>>> 20 > 40 or 20 < 10
False
>>> not 20 > 40
True
【例3.5】 本例演示了比较运算符的基本用法。
实例位置:PythonSamplessrcchapter3demo3.05.py
print(20 == 30) # 判断20和30是否相等,运行结果:False
x = 20
y = 40
print(x < y) # 判断x是否小于y,运行结果:True
if x > y: # 条件不满足
print(“x > y”)
else: # 条件满足
print(“x <= y”)
s1 = “hello”
s2 = “Hello”
if s1 >= s2 and x > y: # 条件不满足
print(“满足条件”)
elif not s1 < s2: # 条件满足
print(“基本满足条件”)
else: # 条件不满足
print(“不满足条件”)
程序运行结果如图3-5所示。
图3-5 比较运算符演示
3.4.5 断言
断言(assertions)的使用方式类似于if语句,只是在不满足条件时,会直接抛出异常。类似于下面的if语句(伪代码):
if not condition: # 如果不满足条件,会直接抛出异常,程序会中断
crash program
那么究竟为什么需要这样的代码呢?主要是因为需要监测程序在某个地方是否满足条件,如果不满足条件,应该及时通知开发人员,而不是将这些bug隐藏起来,直到关键的时刻再崩溃。
其实在TDD(test-driven development,测试驱动开发)中经常使用断言,TDD会在程序发现异常时执行断言,并抛出异常。
在Python语言中,断言需要使用assert语句,在assert关键字的后面指定断言的条件表达式。如果条件表达式的值是False,那么就会抛出异常。而且断言后面的语句都不会被执行,相当于程序的一个断点。
>>> value = 20
>>> assert value < 10 or value > 30 # 条件不满足,会抛出异常
Traceback (most recent call last):
File “”, line 1, in
AssertionError
>>> assert value < 30 # 条件满足,会正常执行后面的语句
可以看到,value变量的值是20,而assert后面的条件是“value < 10 or value > 30”,很明显,条件不满足,所以在断言处会抛出异常。而后面的断言,条件是“value < 30”,这个条件是满足的,所以在断言后面的语句都会正常执行。
当断言条件不满足时抛出异常,在默认情况下,只显示了抛出异常的位置,并没有显示抛出异常的原因,所以为了异常信息更明确,可以为assert语句指定异常描述。
>>> value = 20
>>> assert value < 10 or value > 30, ‘value值必须在10~20’ # 为断言指定异常描述信息
Traceback (most recent call last):
File “”, line 1, in
AssertionError: value值必须在10~20 # 显示了异常描述信息
【例3.6】 本例演示了断言的用法。
实例位置:PythonSamplessrcchapter3demo3.06.py
name = “Bill” # 定义变量name
assert name == “Bill” # 断言条件表达式的值是True,继续执行下面的语句
age = 20 # 定义变量age
# 断言条件表达式的值是False,抛出异常,后面的代码不会被执行
assert 0 < age < 10, “年龄必须小于10岁”
print(“hello world”) # 这行代码不会被执行
程序运行结果如图3-6所示。
图3-6 断言的测试结果
3.5 循环
现在已经知道了如何使用if语句让程序沿着不同的路径执行,不过程序的用处就是利用CPU和GPU强大的执行能力不断重复执行某段代码,想想Google的AlphaGo与柯洁的那场人机大战,尽管表面上是人工智能的胜利,其实人工智能只是算法,人工智能算法之所以会快速完成海量的数据分享,循环在其中的作用功不可没。
对于初次接触程序设计的读者,可能还不太理解循环到底是什么东西。下面先看一下循环的伪代码。
1. 查看银行卡余额
2. 没有发工资,等待1分钟,继续执行1
3. Oh,yeah,已经发工资了,继续执行4
4. 去消费
可以看到,这段伪代码重复展示了一个循环到底是怎样的。对于一个循环来说,首先要有一个循环条件。如果条件为True,继续执行循环,如果条件为False,则退出循环,继续执行循环后面的语句。对于这段伪代码来说,循环条件就是“是否已经将工资打到银行卡中”,如果银行卡中没有工资,那么循环条件为True,继续执行第1步(继续查看银行卡余额),期间会要求等待1分钟,其实这个过程可以理解为循环要执行的时间。如果发现工资已经打到银行卡上了,那么循环条件就为False,这时就退出循环,去消费。
在Python语言中,有两类语句可以实现这个循环操作,这就是while循环和for循环。本节将详细讲解这两类循环的使用方法。
3.5.1 while循环
为了更方便理解while循环,下面先用“笨”方法实现在Python控制台输出1~10共10个数字。
print(1)
print(2)
print(3)
print(4)
print(5)
print(6)
print(7)
print(8)
print(9)
print(10)
可以看到,在上面这段代码中,调用了10次print函数输出了1~10共10个数字,不过这只是输出了10个数字,如果要输出10 000个或更多数字呢?显然用这种一行一行写代码的方式实现相当烦琐,下面就该主角while循环出场了。
现在就直接用Python代码解释一下while循环的用法。
x = 1
while x <= 10:
print(x)
x = 1
可以看到,while关键字的后面是条件表达式,后用冒号(:)结尾,这说明while循环也是一个代码块,因此,在while循环内部的语句需要用缩进的写法。
在上面的代码中,首先在while循环的前面定义一个x变量,初始值为1。然后开始进入while循环。在第1次执行while循环中的语句时,会用print函数输出x变量的值,然后x变量的值加1,后while循环中的语句第1次执行完毕,然后会重新判断while后面的条件,这时x变量的值是2,x <= 10的条件仍然满足,所以while循环将继续执行(第2次执行),直到while循环执行了10次,这时x变量的值是11,x <= 10不再满足,所以while循环结束,继续执行while后面的语句。
while循环是不是很简单呢?其实下一节要介绍的for循环也并不复杂,只是用法与while循环有一些差异。
3.5.2 for循环
while循环的功能非常强大,它可以完成任何形式的循环,从技术上说,有while循环就足够了,那么为什么还要加一个for循环呢?其实对于某些循环,while仍然需要多写一些代码,为了更进一步简化循环的代码,Python语言推出了for循环。
for循环主要用于对一个集合进行循环(序列和其他可迭代的对象),每次循环,会从集合中取得一个元素,并执行一次代码块。直到集合中所有的元素都被枚举(获得集合中的每一个元素的过程称为枚举)了,for循环才结束(退出循环)。
在使用for循环时需要使用到集合的概念,由于现在还没有讲到集合,所以本节会给出简单的集合(列表)作为例子,在后面的章节中,会详细介绍集合与for循环的使用方法。
在使用for循环之前,先定义一个keywords列表,该列表的元素是字符串。然后使用for循环输出keywords列表中的所有元素值。
>>> keywords = [‘this’, ‘is’, ‘while’, ‘for’,’if’] # 定义一个字符串列表
>>> for keyword in keywords: # 用for循环输出列表中的元素
… print(keyword)
…
this
is
while
for
if
上面这段for循环的代码非常好理解,for语句中将保存集合元素的变量和集合变量用in关键字分隔。在本例中,keywords是集合,当for循环执行时,每执行一次循环,就会依次从keywords列表中获取一个元素值,直到迭代(循环的另一种说法)到列表中的后一个元素if为止。
可能有的读者会发现,for循环尽管迭代集合很方便,但可以实现while循环对一个变量进行循环吗?也就是说,变量在循环外部设置一个初始值,在循环内部,通过对变量的值不断改变来控制循环的执行。其实for循环可以用变通的方式来实现这个功能,可以想象,如果定义一个数值类型的列表,列表的元素值就是1~10,那么不就相当于变量x从1变到10了吗!
>>> numbers = [1,2,3,4,5,6,7,8,9,10]
>>> for number in numbers:
… print(number, end=” “) # 输出1~10共10个数字
…
1 2 3 4 5 6 7 8 9 10 >>>
如果使用这种方式,从技术上说是可以实现这个功能的,不过需要手工填写所有的数字太麻烦了,因此,可以使用一个range函数来完成这个工作。range函数有两个参数,分别是数值范围的小值和值加1。要注意,range函数会返回一个半开半闭区间的列表,如果要生成1~10的列表,应该使用range(1, 11)。
>>> for num in range(1,11): # 用range函数生成元素值为1~10的列表,并对这个列表进行迭代
… print(num, end=” “)
…
1 2 3 4 5 6 7 8 9 10 >>>
【例3.7】 本例演示了使用顺序结构、while循环和for循环输出相邻数字的方法,其中for循环使用了range函数快速生成一个包含大量相邻数字的列表,并对这些列表进行迭代。
实例位置:PythonSamplessrcchapter3demo3.07.py
print(1,end=” “)
print(2,end=” “)
print(3,end=” “)
print(4,end=” “)
print(5,end=” “)
print(6,end=” “)
print(7,end=” “)
print(8,end=” “)
print(9,end=” “)
print(10)
# 用while循环输出1~10
print(“用while循环输出1~10”)
x = 1
while x <= 10:
print(x,end=” “)
x = 1
# 定义一个列表
numbers = [1,2,3,4,5,6,7,8,9,10]
print(“n用for循环输出列表中的值(1~10)”)
for num in numbers:
print(num, end= ” “)
# 用range函数生成一个元素值从1~9999的列表
numbers = range(1,10000)
print(“n用for循环输出列表中的值(1~9999)”)
for num in numbers:
print(num, end= ” “)
print(“n用for循环输出列表中的值的乘积(1~99)”)
# 用range函数生成一个元素值为0~99的列表,并对该列表进行迭代
for num in range(100): # range函数如果只指定一个参数,产生的列表元素值从0开始
print(num * num, end= ” “)
程序运行结果如图3-7所示。
图3-7 用while和for循环输出相邻数字
3.5.3 跳出循环
在前面介绍的while循环中,是通过while后面的条件表达式的值确定是否结束循环的,不过在很多时候,需要在循环体内部之间跳出循环,这就要使用到break语句。
>>> x = 0
>>> while x < 100:
… if x == 5:
… break;
… print(x)
… x = 1
…
0
1
2
3
4
在上面的代码中,while循环的条件语句是x < 100,而x变量的初始值是0,因此,如果在while循环中,每次循环都对x变量值加1,那么while循环会循环100次。不过在while循环中通过if语句进行了判断,当x的值是5时,执行break语句退出循环。所以这个while循环只会执行6次(x从0到5),当执行到后一次时,执行了break语句退出while循环,而后面的语句都不会调用,所以这段程序只会输出0到4共5个数字。
与break语句对应的还有另外一个continue语句。与break语句不同的是,continue语句用来终止本次循环,而break语句用来彻底退出循环。continue语句终止本次循环后,会立刻开始执行下一次 循环。
>>> x = 0
>>> while x < 3:
… if x == 1:
… continue;
… print(x)
… x = 1
…
0
在上面的代码中,当x等于1时执行了continue语句,因此,if条件语句后面的所有语句都不会执行,while循环会继续执行下一次循环。不过这里有个问题,当执行这段代码时,会发现进入死循环了。所谓死循环,是指while循环的条件表达式的值永远为True,也就是循环永远不会结束。死循环是在使用循环时经常容易犯的一个错误。
现在来分析一下这段代码。如果要让while循环正常结束,x必须大于或等于3,但当x等于1时执行了continue语句,所以if语句后面的所有语句在本次循环中都不会被执行了,但while循环后一条语句是x = 1,这条语句用于在每次循环中将x变量的值加1。但这次没有加1,所以下一次循环,x变量的值仍然是1,也就是说,if语句的条件永远满足,因此,continue语句将永远执行下去,所以x变量的值永远不可能大于或等于3了。终导致的后果是while循环中的语句会永远执行下去,也就是前面提到的死循环。
解决的方法也很简单,只要保证执行continue语句之前让变量x加1即可。或者将x = 1放到if语句的前面,或放到if语句中。
>>> x = 0
>>> while x < 3:
… if x == 1:
… x = 1 # 需要在此处为x加1,否则将进入死循环
… continue
… print(x)
… x = 1
…
0
2
break和continue语句同样支持for循环,而且支持嵌套循环。不过要注意,如果在嵌套循环中使用break语句,那么只能退出当前层的循环,不能退出外层的循环。在实例3.8中会演示循环更复杂的使用方法。
【例3.8】 本例除了演示while和for循环的基本用法以外,还在满足一定条件的前提下,通过break语句终止了整个while和for循环,以及使用continue语句终止了while和for语句的本次循环,后在while循环中嵌套了一个for循环,从而形成一个嵌套循环,在这个嵌套循环中,输出了二维列表中的所有元素值。在Python语句中,嵌套循环可以嵌套任意多层的循环。
实例位置:PythonSamplessrcchapter3demo3.08.py
x = 0
while x < 100: # 开始while循环
if x == 5: # 当x == 5时终止循环
break;
print(x, end=” “)
x = 1
names = [“Bill”, “Mike”, “Mary”] # 定义一个列表变量
print(“nbreak语句在for循环中的应用”)
for name in names: # 对names列表进行迭代
if not name.startswith(“B”): # 遇到列表元素值不是以B开头的,就终止for循环
break;
print(name)
print(“break语句在for循环中的应用”)
for name in names: # 对names列表进行迭代
# 遇到列表元素值以B开头的,会跳过本次循环,继续执行下一次循环
if name.startswith(“B”):
continue;
print(name, end=” “)
print(“n嵌套循环”)
arr1 = [1,2,3,4,5]
arr2 = [“Bill”, “Mary”, “John”]
arr = [arr1, arr2] # 定义一个二维列表变量
i = 0;
while i < len(arr): # 使用嵌套循环枚举二维列表中的每一个元素值
for value in arr[i]:
print(value, end = ” “) # 输出二维列表中的元素值
i = 1
print()
程序运行结果如图3-8所示。
图3-8 循环演示的输出结果
3.5.4 循环中的else语句
前面讲过,通过break语句可以直接退出当前的循环,但在某些情况下,想知道循环是正常结束的,还是通过break语句中断的,如果使用传统的方法,会有如下代码。
import random # 导入随机数模块
x = 0
break_flag = False # 设置是否使用break语句中断循环的标志变量
while x < 10:
x = 1
if x == random.randint(1,20): # 产生一个1到20的随机整数
break_flag = True # 如果循环中断,将标志设为True
print(x)
break;
if not break_flag: # 如果标志为False,表示循环是正常退出的
print(“没有中断while循环”)
其实有更简单的写法,就是为while循环加一个else子句,else子句的作用仅仅是while正常退出时执行(在循环中没有执行break语句)。else子句可以用在while和for循环中。else子句在循环中的用法请详见实例3.9。
【例3.9】 本例会在while和for语句中加上else子句,并通过一个随机整数决定是否执行break语句退出循环。如果程序是正常退出循环的(条件表达式为False时退出循环),会执行else子句代 码块。
实例位置:PythonSamplessrcchapter3demo3.09.py
x = 0
while x < 10:
x = 1
if x == random.randint(1,20):
print(x)
break;
else: # while循环的else子句
print(“没有中断while循环”)
numbers = [1,2,3,4,5,6]
for number in numbers:
if number == random.randint(1,12):
print(number)
break;
else: # for循环的else子句
print(“正常退出循环”)
要注意,由于这段代码使用了随机整数,所以每次执行的结果可能会不一样。例如,图3-9就是一种运行结果。
图3-9 在循环中使用else子句
3.6 使用exec和eval执行求值字符串
使用过JavaScript语言的读者应该对其中的eval函数印象深刻。eval函数可以将一个字符串当作JavaScript代码执行,也就是说,可以动态执行JavaScript代码。其实Python语言也有类似的功能,这就是exec函数。
>>> exec(‘i = 20’)
>>> exec(‘print(i)’)
20
>>> print(i * i)
400
可以看到上面的代码中,调用了两次exec函数,该函数的参数是字符串类型的值,在本例中是两句合法的Python语句。exec函数成功地执行了这两条语句,并输出了终的结果。从这一点可以看出,exec函数不仅可以执行Python代码,还可以共享上下文,而且通过exec函数执行Python代码,与直接通过Python解释器执行是完全一样的。上下文都是共享的。所以后用print函数输出i * i的结果是400。
不过使用exec函数执行Python代码要注意,尽可能不要让用户可以在全局作用域下执行Python代码,否则可能会与命名空间冲突。
>>> from random import randint
>>> randint(1,20)
11
>>> exec(‘randint = 30’)
>>> randint(1,20)
Traceback (most recent call last):
File “”, line 1, in
TypeError: ‘int’ object is not callable
在上面的代码中,导入了random模块中的randint函数,该函数用于返回一个随机整数。但在用exec函数执行的Python代码中,将randint函数作为一个变量赋值了,因此在后面的代码中就无法使用randint函数随机生成整数了。为了解决这个问题,可以为exec函数指定第2个参数值,用来表示放置exec函数执行的Python代码的作用域(一个字典)。
>>> from random import randint
>>> randint(1,20)
5
>>> scope={}
>>> exec(‘randint = 30’,scope)
>>> randint(1,20)
1
>>> scope.keys()
dict_keys([‘__builtins__’, ‘randint’])
可以看到,在上面的代码中,为exec函数指定了第2个参数(一个字典类型的变量)。这时randint = 30设置的randint变量实际上属于scope,而不是全局的,所以与randint函数并没有冲突。使用scope.keys函数查看scope中的key,会看到randint。
其实exec函数还有第3个参数,用于为exec函数要指定的Python代码传递参数值。
>>> a = 20
>>> args = {‘a’:20,’b’:30}
>>> scope = {}
>>> exec(‘print(a b)’, scope, args)
50
在上面的代码中,exec函数要执行的代码是print(a b),这里的a和b是两个变量,不过这两个变量的定义代码并不是由exec函数执行的,而是在调用exec函数前通过args定义的,args是一个字典,其中有两个key:a和b,它们的值分别是20和30。exec会根据字典的key对应要执行代码中的同名变量,如果匹配,就会将字典中相应的值传入要执行的代码。
在Python语言中还有另外一个函数eval。这个函数与exec函数类似,只是eval是用于执行表达式的,并返回结果值。而exec函数并不会返回任何值,该函数只是执行Python代码。可以利用eval函数的特性实现一个可以计算表达式的计算器。另外,eval也可以像exec函数一样,指定scope和为要执行的代码传递参数值。
>>> eval(‘1 2 – 4’)
-1
>>> eval(‘2 * (6 – 4)’)
4
>>> scope={‘x’:20}
>>> args={‘y’:40}
>>> eval(‘x y’, scope, args)
60
【例3.10】 本例将利用exec函数实现一个Python控制台。可以在控制台中输入任意多条Python语句,然后按Enter键执行前面输入的所有Python语句。
实例位置:PythonSamplessrcchapter3demo3.10.py
scope = {}
codes = “” # 用于保存输入的所有代码
print(“>>>”,end=””) # 输出Python控制台提示符
while True:
code= input(“”) # 输入每一行代码
if code == “”: # 如果输入的是空串,会执行以前输入的所有Python代码
exec(codes, scope) # 执行以前输入的所有Python代码
codes = “” # 重置codes变量,以便重新输入Python代码
print(“>>>”,end=””) # 继续输出Python控制台提示符
continue # 忽略后面的代码
codes = code “n” # 将输入的每一行代码首尾连接,中间换行
这个Python控制台程序与执行python命令进入的控制台程序类似,只是并不像python命令进入的Python控制台一样输入一条语句就执行一条语句,而是输完一起执行。
程序运行结果如图3-10所示。
图3-10 自制Python控制台
3.7 小结
本章主要介绍了流程控制语句(条件语句和循环语句),也可以将这种语句称为复合语句。通过设定条件,可以让程序沿着某个路径运行,并在一定条件下,不断重复执行某段程序,直到条件为False时退出循环。直到现在为止,Python程序基础的部分才算告一段落,有了流程控制语句,就可以通过更复杂的操作控制后面介绍的数据结构(列表、对象、集合等)。
3.8 实战与练习
本章练习题,除了配有答案(源代码)外,还会在赠送的视频课程中讲解。
1. 编写Python程序,实现判断变量x是奇数还是偶数的功能。
答案位置:PythonSolutionssrcchapter3practicesolution3.1.py
2. 改写第1题,变量x需要从Python控制台输入,然后判断这个x是奇数还是偶数,并且需要将这一过程放到循环中,这样可以不断输入要判断的数值。直到输入end退出循环。输入过程如图3-11所示。
图3-11 判断x是奇数还是偶数的输入过程
答案位置:PythonSolutionssrcchapter3practicesolution3.2.py
3. 编写Java程序,使用while循环打印一个菱形。菱形要星号(*)打印。菱形的行数需要从Python控制台输入。行数必须是奇数。
当输入3时,会打印出如图3-12所示的菱形;当输入11时,会打印出如图3-13所示的菱形。
图3-12 打印3行菱形
图3-13 打印11行菱形
答案位置:PythonSolutionssrcchapter3practicesolution3.3.py
4. 利用Python语言中的eval函数编写一个控制台版的计算器,可以计算Python表达式,并输出计算结果。需要通过循环控制计算器不断重复输入表达式,直到输入end,退出计算器。输入过程如图3-14所示。
图3-14 计算器输入过程演示
答案位置:PythonSolutionssrcchapter3practicesolution3.4.py
所谓全栈编程语言,就是指这种编程语言适合的领域非常多,例如Python、JavaScript、Java都可以称为全栈编程语言,因为这些编程语言都适合于至少3个以上的领域。Python适合于GUI、服务端、网络爬虫、深度学习,JavaScript就更广了,除了Python适合的领域,还适合移动开发、区块链等领域。其实目前大多数编程语言都可以编写多个领域的应用,区别只是在难易程度和开发效率上。Python语言之所以现在如此之火,除了Python语言本身容易学习,开发效率高以外,还依赖于大量的第三方模块的支持。
TDD是一种开发方式,简单地说,就是在正式开发之前,先确定关键点,并事先指定这些关键点什么样是正常的,什么样是异常的。例如,age变量是一个关键点,该变量值必须满足age >= 18才是正常的。如果程序由于某些原因(可能是修改程序,修改数据库或其他原因),age小于18了,这时TDD就会通知开发人员,age变量有异常。因此,通过TDD可以及时发现程序中的bug或异常,以便及时处理。也就是在开发程序之前,为程序画了个安全区域,如果越过了安全区域,开发人员就会知晓。
二维列表相当于二维表,可以想象一下Excel中的表格。可以把二维列表中的每一个元素值都看成一个一维列表,也就是说,二维列表是一维列表的集合。关于二维列表的具体细节会在后面的章节详细讲解。
字典是集合的一种,通过关键字(key)查找值(value),在Python语言中用一对花括号({})定义字典变量,key和value之间用冒号(:)分隔,多个key-value之间用逗号分隔。关于字典的详细信息会在后面的章节介绍。
andy735757 –
内容全面,资源丰富,是python入门的好资料,还有实战的分析项目,比单调的只讲基础好太多了,非常值得入手。
昕梅 –
内容翔实而且较为全面,深入浅出,新手学习入门快。例题丰富,由易到难,指导性很强。配合教学视频学习,更加快捷高效。
找乐天使 –
基础到精通,图书加视频,讲的很透彻,有经验或无基础的人,都是不错的资料。着急看,等不到双十一了,原价购买的,不过很值。