学习编程第一步 零基础上手Python开发

学习编程第一步
零基础上手 Python 开发



[英] 罗伯 • 麦尔斯(Rob Miles)

郭俊凤


北 京
Authorized translation from the English language edition, entitled BEGIN TO CODE WITH
PYTHON, 1st Edition, 9781509304523 by MILES, ROB, published by Pearson Education, Inc,
publishing as Microsoft Press, Copyright © 2018.
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording or by any information storage
retrieval system, without permission from Pearson Education, Inc.CHINESE SIMPLIFIED language
edition published by TSINGHUA UNIVERSITY PRESS LIMITED, Copyright © 2018.
本书封面贴有清华大学出版社防伪标签,无标签者不得销售。
版权所有,侵权必究。侵权举报电话:
010-62782989 13701121 933
图书在版编目 (CIP) 数据
学习编程第一步 零基础上手 Python 开发 / (英)罗伯•麦尔斯(Rob Miles) 著;曹瑜,
郭俊凤 译. —北京:清华大学出版社, 2018
书名原文: Begin to Code with Python
ISBN 978-7-302-50249-4
Ⅰ. ①学… Ⅱ. ①罗… ②曹… ③郭… Ⅲ. ①软件工具-程序设计 Ⅳ. ①TP311.561
中国版本图书馆 CIP 数据核字(2018)第 103231 号
责任编辑:王 军 于 平
封面设计: 牛艳敏
版式设计: 思创景点
责任校对: 曹 阳
责任印制: 刘海龙

出版发行: 清华大学出版社
网 址: http://www.tup.com.cn, http://www.wqbook.com
地 址: 北京清华大学学研大厦 A 座
邮 编: 100 084
社 总 机: 010-62770175 邮 购: 010-62786544


投稿与读者服务: 010-62776969, c-service@tup.tsinghua.edu.cn

质 量 反 馈: 010-62772015, zhiliang@tup.tsinghua.edu.cn
印 装 者: 三河市君旺印务有限公司





销: 全国新华书店



本: 170mm×240mm 张: 31.25 数: 630 千字


版 次: 2018 年 6 月第 1 版 印 次: 2018 年 6 月第 1 次印刷
印 数: 1~4000
定 价: 79.80 元
产品编号: 078950-01

译 者 序
Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。通过
Python 编程,我们能解决现实生活中的很多问题。自 1991 年问世以来, Python
日益流行,现已成为多个国家计算机教学中的首选入门编程语言之一。 Python 虽
然简单,其设计却十分严谨。 Python 可能没有 C 或 C++这类编译型语言运行速度
那么快,但是 C 和 C++需要你无时无刻地关注数据类型、内存溢出、边界检查等
问题; Python 就像一个贴心的仆人,私下为你处理好这些,而你可将全部心思放
在程序的设计逻辑上。
本书是一本编程启蒙书籍,将为你的编程之旅指明方向,指引你朝着正确的、
有用的目标前进。本书共分三部分。第I部分介绍如何安装和使用编程工具,讲
述 Python 编程语言的基本元素。第 II 部分描述如何利用 Python 编程语言的特点
构建复杂的应用程序;指导你设计、测试 Python 应用程序,并为程序编写文档。
第 III 部分介绍如何使用软件库在图形用户界面中创建应用程序, 如何在网络应用
中将 Python 程序用作客户端和服务器。最后创建充满魅力的游戏。
即使你没有编程经验,也可在本书的指导下编写出解决实际问题的软件。本
书完全颠覆了编程入门书籍,紧跟时代,为当今的编程新手提供深入的讲解,令
其他书籍望尘莫及。本书编排新颖,从“代码分析”“易错之处” “动手练习”
到“专家点津”,无不令人耳目一新。无论你是初出茅庐的新手,还是经验丰富的
编程人员,本书都将赋予你能量、激动和快乐!当你看到其他用户乐于使用你写
的程序做一些有用的事情时,你的内心将是十分甜蜜的。
在这里要感谢清华大学出版社的编辑们,他们为本书的翻译投入了巨大热情
并付出了很多心血。没有他们的帮助和鼓励,本书不可能顺利付梓。翻译过程中,
译者力求翻译表达传神,但是鉴于水平有限,难免出现错误和失误,请不吝指正。
感激不尽!
本书主要内容由曹瑜、郭俊凤翻译,参与本次翻译的还有陈妍、何美英、陈
宏波、熊晓磊、管兆昶、潘洪荣、曹汉鸣、高娟妮、王 燕、谢李君、李珍珍、王
璐、王华健、柳松洋、曹晓松、陈彬、洪妍、刘 芸、邱培强、高维杰、张素英、
颜灵佳、方 峻、顾永湘、孔祥亮,在此一并表示感谢!
最后,希望读者在阅读过程中领略到 Python 语言之美!

作 者 简 介
Rob Miles 在英国赫尔大学讲授编程课程的年限
超过 30 年。他是一位 Microsoft MVP,对编写程序和
创造新事物充满热情。即使在空闲时间,也不忘继续编
写代码。他喜欢编写代码,然后运行这些代码,看看会
有什么结果。他认为编程最富有创意,让你可以一探究
竟。他相信,编程可以构筑未来。
Rob 自诩为一个段子手, 但旁人却从未亲耳听到他
讲的笑话。如果你想进一步接触和了解 Rob,则可访问
他的博客 www.robmiles.com,或通过@RobMiles 在 Twitter 上找到他。

前 言
要对事物一探究竟,编程是最富有创意的活动。为什么这样讲呢?如果你学
习绘画,你可以绘出作品。如果你学习拉小提琴,你能演奏出音乐。但如果你学
习编程,那将是一番新体验(当然,如果愿意,也可编写代码来绘画或演奏)。一
旦踏上编程之旅,你去往哪里将再无限制。新的设备、技术和市场层出不穷,你
的编程技能总有用武之地。
本书是一本编程启蒙书籍,将为你的编程之旅指明方向,指引你朝着正确的、
有用的目标前进。通过学习本书,你将掌握编程技能,并编写出有用的程序。
不过,在出发前,先要声明几个注意点。就像游猎时,导游会向你介绍狮子、
老虎和鳄鱼,我要向你透露一点,我们的旅程并非是一帆风顺的。对于如何解决
问题,编程人员必须稍微转变一下思路,原因是计算机的工作方式与人类不同。
人类可以小心翼翼地完成复杂事情,计算机可极快地完成简单工作。编程人员的
职责是利用计算机的简单能力去解决复杂问题;这就是我们要学的内容。编程人
员取得成功的关键与其他很多职业是类似的。要成为一位闻名世界的小提琴家,
就必须做大量的练习。编程同样如此,只有耗费大量时间处理程序,才能掌握编
程技能。当你看到其他用户乐于使用你编写的程序做一些有用的事情时,你的内
心将是十分甜蜜的。
本书的编排方式
本书共分三部分。后一部分建立在前一部分的基础上,以便循序渐进地引导
你成为一名成功的编程人员。首先讲述基本编程指令,这些指令将告知计算机如
何完成任务。最后将讲解如何构建专业软件。
第 I 部分 编程基础知识
第I部分介绍如何安装和使用编程工具,讲述 Python 编程语言的基本元素。
你将学会编写第一个程序,领会所有程序的底层构建方式。你将了解 Python 在编
程语言中的地位和重要性。
第 II 部分 高级编程
第 II 部分描述如何利用 Python 编程语言的特点来构建复杂的应用程序。从中
你将了解到,可将大程序分解为多个较小的元素,也可根据要解决的具体问题创
建自定义数据类型;你将能设计、测试 Python 应用程序,并为程序编写文档。

VI 学习编程第一步 零基础上手 Python 开发
第 III 部分 Python 实战
学会如何自己编写程序后,下一步学习如何使用其他人编写的代码。 Python
的一个重要优势在于: Python 用户可使用大量的软件库。第 III 部分将介绍其中的
很多软件库,并讲述如何使用这些库在图形用户界面中创建应用程序,如何在网
络应用中将 Python 程序用作客户端和服务器。最后将创建充满魅力的游戏。
可将本书第 III 部分作为一个可下载的文档,你可在桌面上打开该文档,体验
所演示的程序,并自行创建应用程序。
学习本书的方式
每一章都讲解有关 Python 编程的新知识,先讲解如何做,然后指导你动手练
习并自行创建程序。在这本精心撰写的书籍中,没有哪一页是多余的。不过,你
也可根据自己的需要选学。
你可从头到尾阅读本书,这样,你可慢慢消化更多知识,直至编写能够使用
的程序。就像骑自行车一样,从做中学。为此,你必须投入时间,不断练习。本
书将指导你掌握知识,使你信心百倍地着手编程;如果此前你的程序未能如期运
行,你也可从本书中寻找灵感。为此,本书纳入了以下一些特殊段落。
动手练习
没错,从做中学效果最好。全书穿插多个“动手练习”,带你亲手练习编程
技能。每个“动手练习”都首先引入一个示例,然后列出一些你可以自己去尝试
的步骤。创建的代码能在 Windows、 Mac OS 或 Linux 上运行。
代码分析
学习编程的一种绝佳方式是分析其他人编写的代码,并分析其工作原理,有
时需要查明为什么代码不能如期工作。本书包含 150 多个可供你分析的示例程序。
你将推理论证程序的行为、改正错误,并提供改进建议。
易错之处
如果你此前从未听说过程序会失败,那么在编写你的第一个程序之后,你很
快将体验到酸楚。为帮助你处理问题,本书添加了“易错之处”特殊段落,以推
测你可能遇到的问题,并提出解决方案。例如,在介绍新知识点时,总会讨论哪
些地方容易出错;在讨论新功能时,总是告诉你一些需要考虑的事项。
专家点津
我讲授编程课程已 30 年有余,也编写过很多商业程序。我知道,开始时必须
掌握一些要点。“专家点津”预先为你呈现这些信息,使你在学习过程中,可以
像专业开发人员那样考虑问题。其中涵盖的问题十分广泛,从编程到工作态度,
再到哲理。强烈建议你阅读领会这些观点,这样,在未来可节省大量时间!

前 言 VII
软件和硬件要求
为练习本书中的程序,你需要配备一台计算机,并安装一些软件。我恐怕没
法给你提供计算机,但在第 1 章中,你可以了解到从何处获得 Python 工具和 Visual
Studio Code 应用程序;开始创建更大型的应用程序时,这些都必不可少。
使用 PC 或笔记本电脑
可使用 Windows、 Mac OS 或 Linux 来创建和运行本书中的 Python 程序。对
PC 硬件的最低要求如下:
● 1GHz 或主频更高的处理器,最好使用 Intel i5 或更高性能的处理器。
● 至少4GB内存,最好是8GB内存。
● 256GB硬件空间(完整安装Python和Visual Studio Code将占用约1GB的硬
盘空间)。
对于显卡没有具体要求,但编写程序时,更清晰的屏幕当然会好一些。
移动设备
可在移动设备或平板电脑上编写和运行 Python 程序。 如果有一台运行 iOS 的
Apple 设备,建议你使用 Pythonista 应用。如果使用 Android 设备,应使用 Pyonic
Python 3 解释器。
使用 Raspberry Pi
如果手头缺少资金,开始时可使用最廉价的 Raspberry Pi(运行 Raspbian 操作
系统),其中内置 Python 3.6 和 IDLE 开发环境。
源代码下载
本书每一章都演示和解释程序,以帮助你理解编程机理。你也可在这些程序
的基础上自行编写其他程序,可访问 https://aka.ms/BeginCodePython/downloads,
或扫描本书封底的二维码,下载本书的示例代码。
可按第 1 章的说明来安装示例程序和代码。
致 谢
感谢 Laura Norman 给予我撰写本书的机会,感谢 Dan Foster 和 Rick Kughen
对本书的整理和编辑,感谢 John Ray 富有建设性的精辟技术建议,感谢 Tracey
Croom、 Becky Winter 和 Rob Nance 的排版和加工。
最后感谢妻子 Mary 的支持,你为我沏好一杯又一杯清茶,还为我烘焙软饼,
谢谢你的爱。

VIII 学习编程第一步 零基础上手 Python 开发
勘误、更新和相关支持
我们已经尽最大努力,确保本书的信息正确无误。可访问 https://aka.ms/
BegintoCodePython/errata 来获得本书的更新信息,其中包括已提交的勘误和相关
的更正意见。
如果你发现了未在勘误表中列出的其他错误,也可将其提供给以上网页。
如果需要其他支持,可给 Microsoft Press Book Support 发送电子邮件:
mspinput@microsoft.com。
请注意,上述地址不提供 Microsoft 软件和硬件支持。如果需要获得有关
Microsoft 软件和硬件的帮助,可访问 http://support.microsoft.com。
获得 MTA 认证
MTA(Microsoft Certified Professional)计划旨在使你获得技术认证。通过
98-381 考试“Introduction to Programming Using Python”, 你将获得 MTA 的 Python
编 程 认 证 , 可 通 过 以 下 网 址 了 解 考 试 详 情 : https://www.microsoft.com/en-us/
learning/exam-98-381.aspx。
为帮助你尽量通过学习本书获得MTA认证,这里将考点与本书素材一一对应
列出。注意,考点基于2017年10月公布的考试大纲。
认证结构
将认证划分为多个主题,每个主题都占一定比例。你可以阅读每个主题,并
找到与本书对应的素材。下面的表格列出了对应关系。
1) 使用数据类型和运算符执行操作(20%~25%)
该主题与以下几章的关系最密切:第 4 章描述 Python 程序的数据处理要点,
以及如何操纵和存储文本和数值;第 5 章介绍布尔变量类型,讲述如何操作逻辑
值;第 8 章描述如何存储数据集合;第 9 章讲述如何创建和存储数据结构;第 11
章详述 Python 程序中的集合。

考点 本书的对应章节
表达式求值,识别 Python 为每个变量指定
的数据类型。识别 str、 int、 float 和 bool 数
据类型
第 4 章: Python 中的变量
第 4 章:使用文本
第 4 章:使用数值
第 5 章:布尔数据
第 5 章:布尔表达式



前 言 IX
(续表)

考点 本书的对应章节
执行数据和数据类型操作。 将一种数据类型
转换为另一种;构建数据结构;执行索引和
切片操作
第 4 章:将字符串转换为浮点值
第 4 章:在浮点数和整数之间转换
第 4 章:实数和浮点数
第 8 章:列表和销售金额跟踪
第 9 章:使用类存储联系人信息
根据运算符的优先级确定执行顺序: 赋值运
算符(=)、比较运算符、逻辑运算符、算术
运算符、身份运算符(is)、成员运算符(in)
第 4 章:执行计算
第 9 章: Contact 对象和引用
第 11 章:集合和标记
选择适当的运算符取得预期结果: 赋值运算
符、 比较运算符、 逻辑运算符、 算术运算符、
身份运算符(is)、成员运算符(in)
第 4 章:执行计算
第 9 章:布尔表达式


2) 使用决策和循环控制流程(25%~30%)
该主题与以下几章的关系最密切:第 5 章介绍 if 结构;第 6 章讲述用于实现
Python 程序循环的 while 和 for 循环结构。

考点 本书的对应章节
构建和分析使用分支语句的代码段 第 5 章:布尔数据
第 5 章: if 结构
if、 elif、 else、嵌套和复合条件表达式 第 5 章: if 结构
构建和分析执行迭代的代码段 第 6 章: while 结构
第 6 章: for 循环结构
while、 for、 break、 continue、 pass、嵌套的循
环以及包含复合条件表达式的循环
第 6 章: while 结构
第 6 章: for 循环结构
第 8 章:使用冒泡排序法


3) 执行输入和输出操作(20%~25%)
从第 3 章和第 4 章描述的第一个程序开始,本书穿插介绍如何使用控制台输
入和输出函数。第 8 章简要介绍在 Python 程序中使用文件存储,第 9 章进一步介
绍如何使用 Python pickle 库将数据结构保存在文件中。第 10 章详细介绍 Python
程序中的字符串格式化工具。

考点 本书的对应章节
构建和分析执行文件输入和输出操作的代码
段。理解 open、 close、 read、 write、 append、
check existence、 delete、 with 语句
第 8 章:在文件中保存数据
第 9 章:使用 pickle 将联系人信息保存到文
件中



X 学习编程第一步 零基础上手 Python 开发
(续表)

考点 本书的对应章节
构建和分析执行控制台输入和输出操作的代
码段;包括从控制台读取、打印带格式的文
本以及使用命令行参数
第 3 章:使用 print 函数获取程序输出
第 4 章:使用 input 函数读取文本
第 10 章:设置 Python 字符串格式


4) 代码的文档化和结构(15%~20%)
本书强调:代码的结构必须清晰,代码必须进行文档化。第 3 章简要介绍
Python 注释,第 5 章强调良好代码布局的重要性。第 7 章讲述通过 Python 函数完
善程序结构,并描述如何给函数添加文档,作为程序的自我说明。

考点 本书的对应章节
使用注释和文档字符串实现代码段的文档
化。使用缩进、空白、注释和文档字符串;
使用 pydoc 生成文档
第 3 章: Python 注释
第 5 章:缩进文本可导致大问题
第 7 章:为函数添加帮助信息
第 12 章:查看程序文档
构建和分析包含函数定义的代码段:调用签
名、默认值、 return、 def、 pass
第 7 章:函数的组成


5) 故障排除和错误处理(5%~10%)
第 3 章介绍 Python 代码中的语法错误。第 4 章描述数据处理中的运行时错误。
第 6 章和第 7 章讨论应用程序开发环境中产生逻辑错误的原因和后果。第 6 章和
第 10 章讲述 Python 程序如何抛出和管理异常。第 12 章讲述在 Python 程序测试
中使用单元测试。

考点 本书的对应章节
分析、检测和纠正包含以下错误的代码段:
语法错误、逻辑错误、运行时错误
第 3 章:不完整的程序
第 4 章:输入错误和测试
第 5 章:相等和浮点值
第 6 章:看似正确的循环出错了
第 7 章:使用调试器探究程序
第 12 章:程序测试
分析和构建用于处理异常的代码段: try、
except、 else、 finally、 raise
第 6 章:使用异常检测无效编号输入
第 10 章:抛出异常指示错误


6) 使用模块和工具执行操作(1%~5%)
本书使用的很多 Python 模块都以 random 和 time 模块开头。第 13 章使用
random 库的函数来创建 random 工件,第 16 章的时间跟踪应用程序使用 time 库
的函数。

前 言 XI

考点 本书的对应章节
使用内置模块执行基本操作: math、 datetime、
io、 sys、 os、 os.path、 random
第 3 章: random 库
第 3 章: time 库
使用内置模块解决复杂计算问题: math、
datetime、 random
第 10 章: Time Tracker 中的会话跟踪
第 16 章:生成工件


联系我们
Microsoft Press 将“让读者满意”奉为至高无上的宗旨,你的反馈是我们最宝
贵的资产。请通过 https://aka.ms/tellpress 将你对本书的意见发给我们。
为节省时间,其中只有几个简短问题。你的回答将直接反馈到 Microsoft
Press(不需要提供个人信息)。
提前谢谢你的反馈!
另外,你可通过 Twitter(http://twitter.com/MicrosoftPress)与我们交流。

目 录
第Ⅰ部分 编程基础知识
第 1 章 开始使用 Python··············· 3
1.1 什么是 Python····················· 3
1.1.1 Python 的起源 ················· 4
1.1.2 Python 版本 ····················· 4
1.2 打造使用 Python 的场所 ···· 5
1.2.1 获取工具 ························· 5
1.2.2 Python(适用于
Windows PC) ···················
6
1.3 启动 Python························· 8
1.4 本章小结 ····························11
第 2 章 Python 和编程 ················ 13
2.1 编程人员的工作 ················13
2.1.1 编程和规划生日聚会··· 13
2.1.2 编程和问题 ·················· 14
2.1.3 编程人员要善于沟通··· 15
2.2 计算机用于处理数据·········16
2.2.1 机器、计算机和人······· 16
2.2.2 程序用于处理数据······· 18
2.2.3 Python 用于处理数据··· 19
2.3 数据和信息 ························23
2.4 使用 Python 函数 ···············27
2.4.1 ord 函数························ 27
2.4.2 chr 函数························ 28
2.4.3 使用 bin 函数探索数据
存储 ······························
29
2.5 本章小结 ····························30
第 3 章 Python 程序结构 ·············33
3.1 编写首个 Python 程序 ·······33
3.1.1 使用 IDLE 运行 Python
程序·······························
33
3.1.2 使用 print 函数获得程序
输出·······························
37
3.2 使用 Python 库···················42
3.2.1 random 库······················ 42
3.2.2 time 库··························· 45
3.3 Python 注释························46
3.4 从桌面运行 Python············47
3.5 添加一些 snaps 函数··········48
3.5.1 添加 pygame 库············· 48
3.5.2 snaps 函数 ····················· 49
3.6 本章小结····························52
第 4 章 使用变量 ·························55
4.1 Python 中的变量················55
4.2 使用文本····························59
4.2.1 标记字符串的开始和
结束·······························
61
4.2.2 文本中的转义字符········ 62
4.2.3 使用 input 函数读取
文本·······························
63
4.3 使用数值····························65
4.3.1 将字符串转换为整
型值·······························
65
4.3.2 整数和实数 ··················· 66
4.3.3 实数和浮点数 ··············· 67
4.3.4 将字符串转换为浮
点值·······························
71
XIV 学习编程第一步 零基础上手 Python 开发
4.3.5 执行计算 ······················ 72
4.3.6 在浮点数和整数之间
转换 ······························
73
4.4 snaps 函数 get_weather_
temp ····································75
4.5 本章小结 ····························76
第 5 章 在程序中制定决策 ·········· 79
5.1 布尔数据 ····························79
5.1.1 创建布尔变量 ·············· 79
5.1.2 布尔表达式 ·················· 81
5.1.3 比较值 ·························· 83
5.1.4 布尔运算 ······················ 86
5.2 if 结构 ································88
5.2.1 嵌套 if 条件·················· 95
5.2.2 使用逻辑 ······················ 96
5.3 使用决策创建应用程序·····96
5.3.1 设计用户界面 ·············· 97
5.3.2 实现用户界面 ·············· 98
5.3.3 测试用户输入 ·············· 99
5.3.4 完成程序 ······················ 99
5.4 导入 snaps 库 ···················100
5.5 本章小结 ··························103
第 6 章 使用循环执行重复
操作······························ 105
6.1 while 结构 ························105
6.1.1 使用 while 重复执行一
系列语句 ····················
105
6.1.2 处理无效的用户输入 ·· 109
6.1.3 使用异常检查无效编号
输入 ····························
112
6.1.4 异常和编号读取········· 114
6.1.5 处理多个异常 ············ 115
6.1.6 跳出循环 ···················· 116
6.1.7 使用 continue 返回到循环
顶部 ····························
117
6.1.8 重复循环计数 ············ 118
6.2 for 循环结构 ····················120
6.3 使用 snaps 制作数字
闹钟··································123
6.4 本章小结··························124
第 7 章 使用函数简化程序·········125
7.1 函数的组成······················125
7.1.1 使用参数给函数提供
信息·····························
128
7.1.2 函数调用的返回值······ 135
7.2 构建可重用的函数 ··········141
7.2.1 创建文本输入函数······ 141
7.2.2 为函数添加帮助信息·· 142
7.2.3 创建数值输入函数······ 144
7.2.4 将函数转换为 Python
模块·····························
147
7.2.5 使用 IDLE 调试器 ······ 148
7.3 本章小结··························153
第 8 章 存储数据集合 ················155
8.1 列表和销售金额跟踪 ······155
8.1.1 单独变量的局限性······ 157
8.1.2 Python 中的列表 ········· 158
8.1.3 在列表中读取值 ········· 160
8.1.4 使用 for 循环显示
列表·····························
161
8.2 将程序重构为函数 ··········162
8.2.1 创建占位函数 ············· 165
8.2.2 创建用户菜单 ············· 165
8.3 使用冒泡排序法 ··············167
8.3.1 使用测试数据初始化
列表·····························
167
8.3.2 按降序排序列表 ········· 168
8.3.3 按升序排序列表 ········· 172
8.3.4 查找最大值和最
小值·····························
173
8.3.5 计算销售总额和平均
销售额·························
174
目 录 XV
8.3.6 完成程序 ···················· 174
8.4 在文件中存储数据 ··········175
8.4.1 写入文件 ···················· 176
8.4.2 写入销售金额 ············ 179
8.4.3 从文件读取 ················ 180
8.4.4 读取销售金额 ············ 182
8.4.5 处理文件错误 ············ 183
8.5 存储数据表 ······················185
8.6 将列表用作查找表 ··········188
8.7 元组··································189
8.8 本章小结 ··························191
第 II 部分 高级编程
第 9 章 使用类存储数据············ 197
9.1 生成 Tiny Contacts
应用 ··································197
9.1.1 生成原型 ···················· 198
9.1.2 在不同的列表中存储联系
人详细信息 ················
200
9.1.3 使用类存储联系人详细
信息 ····························
202
9.1.4 在 Tiny Contacts 程序中
使用 Contact 类 ··········
205
9.1.5 编辑联系人信息········· 207
9.1.6 使用 pickle 将联系人信息
保存到文件中·············
215
9.1.7 使用 pickle 从文件加载
联系人信息 ················
217
9.1.8 给 Tiny Contacts 程序添加
save 和 load 函数········
218
9.1.9 设置类实例 ················ 219
9.2 字典··································223
9.2.1 字典管理 ···················· 225
9.2.2 从函数返回字典········· 225
9.2.3 使用字典存储联系人
信息 ····························
226
9.3 本章小结··························227
第 10 章 使用类创建活动对象 ···229
10.1 创建 Time Tracker··········229
10.1.1 为类添加数据
特性·························
230
10.1.2 创建聚合对象 ········· 231
10.1.3 为类创建方法
特性·························
232
10.1.4 为方法添加验证
代码·························
234
10.1.5 防止数据特性受到
破坏·························
243
10.1.6 受保护的方法 ········· 246
10.2 创建类属性 ····················246
10.3 扩展类设计 ····················250
10.4 类中的__str__方法········257
10.5 Time Tracker 中的法庭工作
时长跟踪························260
10.5.1 Python map 函数 ····· 264
10.5.2 Python join 方法 ······ 269
10.6 使用 snaps 制作音乐······270
10.7 本章小结························273
第 11 章 设计面向对象的解决
方案·····························277
11.1 Fashion Shop 应用
程序································277
11.1.1 应用程序数据
设计 ·························
279
11.1.2 面向对象的设计······ 279
11.1.3 创建超类和子类······ 282
11.1.4 数据设计总结·········· 295
11.1.5 实现应用程序
行为 ························
302
11.1.6 将对象作为组件······ 305
11.2 创建 FashionShop
组件································306

XVI 学习编程第一步 零基础上手 Python 开发
11.3 设计类 ····························314
11.4 Python 集合 ····················315
11.4.1 集合和标签············· 318
11.4.2 集合与类层次结构的
对比 ························
321
11.5 本章小结 ························324
第 12 章 Python 应用程序········· 327
12.1 高级函数 ························327
12.1.1 函数引用 ················ 327
12.1.2 使用 lambda
表达式 ····················
332
12.1.3 迭代器函数和 yield
语句 ························
335
12.1.4 使用任意实参数量的
函数 ························
340
12.2 模块和包 ························343
12.2.1 Python 模块 ············ 343
12.2.2 给 BTCInput 添加
readme 函数············
343
12.2.3 将模块作为程序
运行 ························
344
12.2.4 检测模块是否作为程序
执行 ························
344
12.2.5 创建 Python 包 ······· 345
12.2.6 导入包中的模块····· 347
12.3 程序测试 ························350
12.3.1 Python assert 语句··· 351
12.3.2 Python unittest
模块 ························
352
12.3.3 创建测试 ················ 355
12.4 查看程序文档 ················356
12.5 本章小结 ························361
第 III 部分 Python 实战
第 13 章 Python 和图形用户
界面 ···························· 365
13.1 Visual Studio Code ·········365
13.1.1 安装 Visual Studio
Code························
366
13.1.2 在 Visual Studio Code 中
安装 Python
Extension ················
366
13.1.3 创建项目文件夹······ 367
13.1.4 创建程序文件 ········· 368
13.1.5 调试程序 ················· 369
13.1.6 其他 Python
编辑器·····················
373
13.2 使用 Tkinter 创建图形用户
界面································373
13.2.1 创建图形应用程序·· 379
13.2.2 网格布局 ················· 380
13.2.3 创建事件处理器······ 382
13.2.4 创建 mainloop ········· 383
13.2.5 处理 GUI 中的
错误·························
383
13.2.6 显示消息框 ············· 385
13.2.7 在画布上绘制 ········· 388
13.2.8 Tkinter 事件············· 391
13.2.9 创建绘制程序 ········· 392
13.2.10 输入多行文本········ 394
13.2.11 在 Frame 中组合显示
元素 ·······················
396
13.2.12 使用 GUI 创建可编辑
的 StockItem···········
396
13.2.13 创建一个 Listbox
选择器····················
402
13.2.14 包含 GUI 的应用
程序 ·······················
408
13.3 本章 小结 ···························410
第 14 章 Python 程序用作网络
客户端 ·························413
14.1 计算机网络 ····················413

目 录 XVII
14.2 从 Python 使用 Web ·······422
14.2.1 读取网页 ················ 422
14.2.2 使用基于 Web 的
数据 ························
423
14.3 本章小结 ························426
第 15 章 Python 程序用作网络
服务器························· 429
15.1 在 Python 中创建 Web
服务器····························429
15.1.1 一台基于套接字的
小型服务器·············
429
15.1.2 Python Web 服务器··· 433
15.1.3 通过文件支持
网页 ························
435
15.1.4 从 Web 用户获取
信息 ························
439
15.2 在 Web 上托管 Python
应用程序························443
15.3 本章小结 ························443
第 16 章 使用 pygame 创建
游戏 ···························· 445
16.1 开始使用 pygame···········445
16.2 使用 pygame 绘图··········451
16.2.1 图像文件类型 ········· 451
16.2.2 将图像加载到
游戏中 ·····················
452
16.2.3 使图像能够移动······ 454
16.3 从 pygame 获取用户
输入································455
16.4 创建游戏 Sprite··············457
16.4.1 添加玩家 Sprite ······· 461
16.4.2 控制玩家 Sprite ······· 463
16.4.3 添加 Cracker Sprite·· 464
16.4.4 添加大量 Sprite
实例 ························
465
16.4.5 捕获薄脆饼干 ········· 466
16.4.6 添加西红柿杀手······ 469
16.5 完成游戏························472
16.5.1 添加启动屏幕 ········· 472
16.5.2 结束游戏 ················· 475
16.5.3 游戏记分 ················· 476
16.6 本章小结························477

第Ⅰ部分
编程基础知识
我们的编程启蒙之旅就此开始!首先介绍计算机实际所做的
工作以及编程语言的含义,然后指导你安装所需的编程工具。接
下来,你将看到使用 Python 语言的第一个步骤,以便告知计算机
为你做事。
第 I 部分讲解所有程序使用的 Python 编程语言的基本元素。


开始使用 Python
本章主要内容
首先介绍我们要学习的 Python 编程语言,然后讨论使用什么类型的计算机来
编写程序,以及如何查找和安装用来构建代码的工具。还将开始与
Python Shell
交互,并体会编程语言设计者的幽默感。
1.1 什么是 Python
在开始学习 Python 前,有必要考虑 Python 到底是什么。 Python 是一门编程
语言,换句话说,它是用于编写程序的语言。程序是一组指令,告诉计算机如何
完成工作。我们无法使用诸如“英语”的语言做到这一点,因为对计算机而言,
严格意义上的英语实在是太难理解了。例如,请看以下医嘱:
Drink your medicine after a hot bath. ( 洗热水澡后服药 )
你当然可以遵从医嘱,洗上一个热水澡,再服下药物。但对计算机而言,则
可能先喝下热洗澡水,然后喝下药物。你可用人性化方式解释上面一句话,因为
英语允许你使用模糊语句。而在设计编程语言时,所写的指令不能有二义性,必
须是准确的。通常这意味着,需要将动作分解为一系列简单步骤:
步骤 1 :洗个热水澡。
步骤
2 :服药。
编程语言要求我们采用上述方式编写指令。Python 是多种编程语言中的一种,
1
4 第 I 部分 编程基础知识
为人们提供了一种告知计算机操作的方式。
在我多年的编程生涯中,学过多种不同的语言,当然,未来还需要学习更多
语言。没有一门语言是完美的。我将每门语言视为一种工具,用于具体的情形;
就像我在砖墙、玻璃板或木块上钻孔时会选用不同工具一样。
论及“最优秀的”编程语言时,很多人都显得十分激动。我也乐于讨论
这个话题,就像我讨论自己最喜欢的小汽车,但我认为这个问题没有定论。我
喜欢 Python,是因为 Python 性能卓越,表达清晰;我喜欢 C#编程语言,是因
为我可以借助它得到结构完好的解决方案;我喜欢 C++编程语言,是由于我可
通过它牢牢控制支持程序运行的硬件……Python 确实有一些令我不满意之
处,但哪门语言不是这样呢?所有编程语言各有千秋,我觉得哪一种都是必不
可少的。
1.1.1 Python 的起源
你可能认为,编程语言就像发射太空火箭,由身穿白大褂、学识渊博的科学
家们设计,他们总能在第一时间将一切处理得井井有条,开发的解决方案也完美
无缺。但事实并非如此。由于多种原因,多年来编程语言一直在发展和完善中。
Guido van Rossum 是 Python 最初的开发者。 1989 年末,即圣诞节期间,公
司放假,他决定用几周时间按自己的爱好开发一个好玩的编程项目。他将这门
语言命名为 Python,这不是因为他喜欢大蟒蛇,而是因为他是英国电视喜剧
Monty Python’s Flying Circus (蒙提·派森的飞行马戏团)的忠实粉丝。凭借其卓越
的性能和简明的风格, Python 语言风靡全球。现在, Python 成为最流行的编程
语言之一。
1.1.2 Python 版本
Python 有很多版本。在编程人员看来,这好像有点儿乱。用一个 Python 版本
编写的程序未必与用另一个 Python 版本编写的程序兼容。不过,如果所有编程人
员都使用相同的 Python 版本,那么 Python 允许在你的程序中使用由其他人编写
的程序,这可以节省大量时间和工作。历经多年的洗练,形形色色的 Python 版本
汇集成两股不同的发展潮流,这在一定程度上简化了开发。
选择 Python 版本时,归结为选择 2.7 版本还是 3.
n 版本(其中, n 是不断递增
的编号)。
● 2.7 版本(长久以来的骨干版本)无疑十分优秀,大量现有的软件都使用 2.7
版本。如果你使用 Python 代码库执行特定任务,库代码很可能是 2.7 版
本的。
● 3.
n 版本(后起之秀)也十分优秀,它去除了很多令人混淆的语言功能。
本书将重点介绍 Python 3. n 版本。你将看到不同版本对程序的影响,另外,
你将考虑如何使用 2.7 版本支持的一些库。
好在两种 Python 版本的程序创建基础是相同的。其实,几乎所有编程语言都
是互通的; 一旦你学会编写 Python 程序, 自然可将技术用于 C++、 C#、 Visual Basic
和 JavaScript 等其他很多编程语言。
一旦你掌握了基本驾驶技术,即可将技术运用于几乎任何交通设备;同样,
你可将 Python 编程技能运用于其他编程语言。开一辆新车时,只需要在启程前找
到各种开关按钮和控制板;在编程领域,情况同样如此。
1.2 打造使用 Python 的场所
如果你是一位大货车长途司机,在国内出租运输货物,当然希望驾驶室内有
舒适的座椅,能看清路况,并能方便地找到和使用控制板。当然,卡车最好有足
够的动力以较快的速度爬山,在蜿蜒的山路上也能自如前行。
同样,如果长时间用键盘敲击程序,也需要有一个舒适的工作场所。安装
好 PC、键盘和显示器;有一把无比舒适的座椅,让你坐几个小时都不会感到
困倦。
写程序时,计算机不必要性能非凡,但为了支持所用的工具,还是要达到合
理的性能标准,内存和 CPU 都要达到一定要求。我建议,设备的最低配置是 CPU
Intel i5(或同等级别的处理器)、 4GB 内存、 256GB 硬盘。使用小型计算机时,开
发难度难免增加,更新程序的时间会延长一些。
所使用的操作系统取决于个人偏好。我喜欢使用 Windows 10,但如果你
喜欢用 Mac OS 或 Linux,也无妨。这三种操作系统都支持 Python 语言及其开
发环境。
1.2.1 获取工具
在开始共享或销售程序之前,必须下载和安装相应的工具。安装过程需要耗
费一定时间,具体时长取决于网络连接速度。个别情况下,下载和安装需要你等
待较长的时间。注意,必须按顺序执行操作。你只需要对要使用的每台计算机执
行一次安装,所以不必心急。
所需要的工具都可供免费下载和安装。如此卓越的软件竟然免费供所有人使
用, 确实令人感到惊异和激动!使用 Python 分发版, 可方便地开始编写程序, Visual
Studio Code 编辑器是创建大型应用程序的理想工具。
对于不同设备,该工具及其获得方式都稍有不同。你可从以下网址下载最新
的指令:

www.begintocodewithpython.com/tools/
1.2.2 Python(适用于 Windows PC)
如果使用 Windows PC,可从 Python 网站下载和安装 Python。从 Python 下载
站点下载安装程序,将其安装在 Windows PC 上。我使用 Microsoft Edge 浏览器。
如果你使用其他浏览器,看到的屏幕将稍有不同。我建议你使用 Microsoft Edge
浏览器执行以下步骤。
务必使用如下官方下载站点,按 Windows 提示运行安装程序:
www.python.org/downloads/
图 1-1 显示了 Python 的下载页面。

图 1-1 Python 下载页面
网页中显示,我正在使用 Windows PC,并提供了两个下载版本。在下载页面
上,我想要安装 Python 3.6.1 版本,因此单击此按钮开始下载,如图 1-2 所示。

图 1-2 单击按钮开始下载
浏览器将询问要对文件执行什么操作。如果你使用 Microsoft Edge,则可
看到上面的对话框。单击 Run 按钮。下载 Python 安装程序后,将开始运行(见
图 1-3)。
Python 安装程序将 Python 下载到你的计算机上,以供使用。可通过多个设置
来更改 Python 的安装方式,也可不作任何更改。此处的唯一变化是选中安装程序
对话框底部的 Add Python 3.6 to PATH 复选框,然后单击 Install Now。系统可能
要求你确认对系统的更改,单击 OK 按钮接受这些更改。

图 1-3 Python 安装程序
在安装的最后,将看到如图 1-4 所示的窗口,单击 Close 按钮关闭窗口。

图 1-4 安装成功
安装临近结束时,屏幕上可能显示消息 Disable path length limit(见图 1-5),这
指 Windows 管理文件引用的方式。如果看到这条消息,单击 Disable path length
limit,然后确认对计算机设置的更改。
安装完成后单击 Close 按钮,关闭安装程序。

图 1-5 单击 Disable path length limit,确认更改
Python 安装程序的问题
Python 下载网页通常可探知你所使用的操作系统,显示的按钮将针对你的计
算机自动指向正确文件。但有时并非如此,你看不到任何直接下载按钮。如果出
现这种情况,只需要从下载页面显示的选项中选择你使用的操作系统,为你的计
算机找到最新的语言版本。 Python 会定期更新, 因此你所看到的版本可能与图 1-1
不同(例如,版本可能是 3.6.3)。这不是问题。只要版本号是 3.
n ,就支持本书使用
的示例程序。
1.3 启动 Python
可启动支持 Python 语言的环境,并与之交互。就像打开了新公寓或新房的前
门,或钻进新购小汽车的车内。
所用的工具称为 IDLE(Integrated Development Learning Environment,集成的
开发学习环境),又称 Eric Idle(Monty Python 剧组的一位成员)。在 IDLE 中,可通
过两种方式与 Python 交互: shell(输入的 Python 命令将立即执行)或文本编辑器(允
许创建程序代码文档)。当今的几乎所有操作系统都支持 IDLE。

打开 IDLE
首先打开 IDLE 环境。在 Windows 10 上单击
Start 按钮,然后在 Python 程序组中找到 IDLE(见
图 1-6)。

有必要在 Start 菜单中添加 IDLE,或将其锁定
到任务栏。为此,右击 IDLE,然后选择对应的选
项即可。
在 Mac OS 或 Linux 上,打开终端,输入 idle,
按下 Enter 键。使用哪种操作系统都可以;IDLE 运行后,可使用屏幕上显示的 IDLE
命令 shell(见图 1-7)。

图 1-7 IDLE shell
shell 内有引擎, IDLE 程序包含 Python 引擎。 Python 引擎运行 Python 程序。
IDLE Python Shell 执行你输入的 Python 命令,将它们输入到 Python 引擎,然后
显示结果。

可将 IDLE shell 比作餐厅服务员。你告诉服务员要吃什么,服务员然后离开
你的座位,转到厨师那里告知,此后将厨师做好的食物端到你的桌上。服务员就
像以厨师为中心的 shell。
可使用 IDLE 向 Python 问好(见图 1-8)。输入 hello,然后按下 Enter 键:

图 1-8 失败的问候
嗯,效果欠佳!作为一条经验法则,如果计算机显示红色消息,通常大事不
妙。这里,一长串红色消息(图 1-7 中的浅色代码部分)指出 Python 不认识单词 hello。
当你输入命令时, Python Shell 后的程序将查阅所知的单词列表, 试图找到匹配者。
列表中并未定义单词 hello,于是 Python 显示这条错误消息。
这就像你向服务员点餐,但厨师不会做。或许 Python Shell 应该显示 I don't
know what 'hello' means,这样更加浅显直白。可以看到,计算机错误消息总将简
单的错误变得十分复杂。
下一章将详述如何使用 Python Shell,来探讨计算机运行程序时到底在做什
么。此处仅输入 import this(见图 1-9),激活“复活节彩蛋”来结束 shell 会话。

图 1-9 微妙的 Python
如果你正在寻找“Python哲理”,那么这就可以算作一条。或许,这也是该
语言“
复活节彩蛋” 历久弥新的原因。如果你觉得一些话讲得过于深奥,不要急,
你将在后续章节了解其中的深意。
1.4 本章小结
在第 1 章中,通过安装 Python 语言和 IDLE 开发环境,打造了一个工作场所。
Python 是一门编程语言,编程语言是英语的简化版本,允许编程人员告知计
算机如何完成任务。
你还与 Python 进行了简单交互,发现仅有善意没有多大帮助作用。相反,你
必须给出完全正确的指令,此后才能愉快地交流。
为加深对本章知识点的理解,请思考以下有关计算机、程序和编程的“深奥”
问题:
“程序”和“应用程序”有什么区别?
当谈论软件时,人们往往交替使用“程序”和“应用程序”这两个词语。我

用“程序”描述一些代码,这些代码指示计算机做什么操作。我用“应用程序”
描述更大和更广的开发范围;“应用程序”将程序代码以及图像和声音等资源集
成在一起,给予用户完整的体验。 “程序”可能非常简单,只是几行 Python 代码。
“人工智能(Artificial Intelligence, AI)”是否意味着终有一天不再需要编写
程序?
这是一个非常深刻的问题。我个人认为,人工智能领域的大量从业人员将使
计算机变得足智多谋。给计算机提供大量信息,并将信息的关联方式告知它们。
基于这些素材,程序可根据陈述的上下文准确地推断和猜测。
人们可“猜测”事物的含义。或许有一天,医生真想让我在服药前喝一些热
洗澡水(根据本章开头所列的指令),而我却错误地领会了医嘱。不过总体来看,
人类存储和综合分析信息的能力要强大得多,在表演技能方面,计算机明显处于
劣势。或许将来某个时候,这种情况会改变。即使在现在,我们也已看到,在某
些技能领域,如财务、医疗诊断和人工智能领域,计算机已经作用非凡。不过,
为将我们想做的事情准确告知计算机, 在相当长的时间内, 都离不开编程人员……
在你还清房贷前,肯定是这样。
IDLE 是编写程序的唯一工具吗?
IDLE 不是唯一工具。可使用许多工具来创建程序。一些工具完全绑定到一种
特定的编程语言,而一些则更通用。我个人喜欢使用 Visual Studio 工具。 Visual
Studio 可用于包括 Python 在内的多种编程语言。不过,对编程新手而言, Visual
Studio 显得复杂一些,就像开着跑车学习驾驶技术一样。本书第 III 部分将介绍
Visual Studio 及其姊妹工具 Visual Studio Code。
如果损坏了程序,我该怎么办?
一些人担心,用计算机程序完成的工作可能“受损”。我过去也担心这一
点。通过始终留一条“后路”,我克服了这种恐惧心理。你或许对此心存恐惧,
现在,你知道如何在计算机上安装 Python。不大可能仅因为在其中运行程序而
损坏 Python 安装;即使不幸真的降临,你损坏了程序,它不能工作了,也不
必过分焦虑,你只需要再安装一次程序的干净副本,然后重新启动即可。

Python 和编程
本章主要内容
你将从本章开始使用 Python 。但在此之前,先来探讨编程人员和计算机程序实
际做的工作。还将分析
Python 编程语言,讨论 Python 在软件开发领域的地位。
2.1 编程人员的工作
如果你此前未编写过程序,不必担心。编程不是火箭科学。在学习编程时,
会对大量的想法和概念感到困惑,这就是难点所在。如果你认为学习编写程序非
常难,自己没有能力从事这项工作,我强烈建议你抛弃这些想法。编程十分容易,
就像为一群小朋友组织生日聚会一样简单。
2.1.1 编程和规划生日聚会
如果要组织一群小朋友参加的生日聚会,就必须确定受邀者。要记住哪位小
朋友爱吃蔬菜比萨,哪几位小朋友如果坐在一起会打闹不休。必须考虑每位小朋
友将什么礼物带回家,每个人在聚会上的分工。还要规划好时间,不要让魔术师
正好赶在饭点到达。为便于规划,你使用图 2-1 所示的列表。编程与此类似,关
键在于“组织”。
如果有能力举办一次聚会,就有能力编写程序。编程会有一些特殊之处,但
基本原理是一样的。由于程序包含可由你创建和管理的元素(与任性的孩子不同),
你可完全掌控所发生的一切。另外,如果编写过一些程序,你便能开始井井有条
2
地处理所有任务;因此,如果有一点儿编程经验,你会成为更优秀的组织者。

图 2-1 规划生日聚会与编程类似,让一切有条不紊地进行
大多数人将编程定义为“做的工作谁也弄不懂,但日进斗金。”我将编程定义
为“为给定的问题找到解决方案,将方案表示为计算机程序可以理解和执行的形
式。”在该定义中,自然包含如下一两个事项:
● 只有你能自行解决问题,此后才能编写程序完成任务。
● 必须让计算机理解你要它执行什么操作。
程序有点像食谱。如果你不知道如何烘焙蛋糕,就无法告诉其他人怎么做。
如果听者不理解诸如“折叠面团,在其中揉糖”的指令,你仍然无法告诉他如何
烘焙蛋糕。
要创建程序,必须拿出一个解决方案,然后将其分解为多个简单步骤,使计
算机可以执行。
2.1.2 编程和问题
不妨将编程人员比作管道工。管道工到达现场时,会背上一包工具和配件。
用一小会儿时间查看管道问题,然后打开工具包,取出不同的工具和配件,将各
部分组合在一起,从而解决问题。编程与此类似。你有一个要解决的问题,你同
样有一包可用的工具,即编程语言。你思考了一会儿,想出解决方案。然后将语
言片段组合在一起解决了问题。编程艺术在于确定你要从工具包中取出哪些工具
来解决每一部分的问题。
编程的有趣之处在于以下艺术:将要解决的问题分成你可交给计算机完成的
一组指令。不过,学习程序并非只是学习编程语言,也不是仅得到一个能解决问
题的程序。编写程序时,你必须考虑诸多事项,其中一些事项并不与手头的问题
直接相关。开始时,假设你为客户编写程序;客户有一个问题,希望你能编写程
序加以解决;还假设客户对计算机的了解不如我们多。
开始时,甚至不会谈及编程语言、计算机类型等;此时务必了解客户的需要。

由于编程人员为能提供方案而沾沾自喜,当收到客户的问题时,他们立即思考解
决方案——几乎是反射性动作。遗憾的是,在很多软件项目中,由于解决了错误
的问题而走向失败。在实际中,针对一个与客户无关的问题提供“完美”解决方
案的例子比比皆是。软件开发人员并未找出哪些是客户需要的或希望得到的;相
反,开发人员创建了自己想要的东西。客户认为:开发人员不再问我了,他们正
在构建正确的解决方案。直到最终交付产品时,真相才浮出水面。编程人员只有
等到真正准确了解客户的需求后,才能着手构建解决方案。
最糟的情形是,你直接对客户说“我可以做到。”相反,你首先应该问“客户
需要这个吗?”“我真正理解问题吗?”提出这些问题是一种自律行为。在解决问
题前,你应该有一个有关问题的严密定义,这个定义既是你可以接受的,也是客
户可以接受的。
在现实中,将此类定义称为“功能设计规范(Functional Design Specification,
FDS)”。 FDS 准确说明客户的需求。你和客户都要签字;如果你能根据设计规范
提供系统,客户必须支付费用。确定规范后,开始考虑解决问题的方式。
你可能认为,如果编写一个自用程序,就没必要写一套规范。这种想法是错
误的。通过编写某种形式的规范,将迫使你周全地考虑问题,也迫使你考虑你的
系统不需要做什么。不管是服务客户,还是编写自用软件,都必须编写清晰的文
档。规范在一开始就说明了对产品的期望。
专家点津
从头到尾少不了规范
我编写过很多商业程序。每次编写程序时,都首先写好周密的规范。即使帮
朋友办事,也照写不误,标准丝毫不降低,甚至会更高。
现代开发技术以客户为中心展开,让客户持续参与设计过程。这些方式非常
有帮助作用,因为在项目之初,往往很难写出明确、周详的规范。作为一名开发
人员,你对客户业务的了解不会那么深,而客户也不了解你用于解决问题的技术
的局限性和可能性。最好构建一系列解决方案版本,与客户一起讨论每个版本的
可行性,再进入下一阶段。我们将这称为“确定原型(prototyping)”。
无论使用哪种编程语言,这都是解决问题的正确方式。无论你做什么事情,包
括组织一次生日聚会,编写周密的规范都是十分重要的。
2.1.3 编程人员要善于沟通
确定客户的需要是任何编程任务中最重要的一环。不过,在其他很多情形中,
与其他人员的交流也很重要。你可能想要说服一个富有的人支持你的下一个宏伟

目标;也可能想说服一名潜在客户,你能给出方案,解决他的问题。
并非所有编程人员一开始就擅长社交。但有一个要点需要记住:沟通技巧是
可以学习的,就像学习一门新的编程语言一样。要更好地沟通,你需要走出自觉
舒适的小天地。第一次,谁也不愿站在大众面前讲话,但通过练习,你将熟练掌
握沟通技能,让自己在生意场上走得更远。
有效沟通同样可扩展到写作方面。能够写文章供他人阅读,本身就是一项有
用的技能;要提高文笔水平,同样需要锻炼。我建议你从今天就开始写博客或写
日志。或许,你写的博客起初只有你母亲才会去看,但务必坚持下去。如果常写
一些自己感兴趣的东西(我喜欢写编程方面的文章,请参见 www.robmiles.com),
你的写作水平将迅速提高。
专家点津
善于沟通的编程人员能揽到更有趣的工作,赚取更丰厚的收入
即使你十分木讷,只偶尔从口中迸出几个单词,或嘟囔几句,但只要能快速
写出满足特定要求的代码,养家糊口就不成问题。但是,那些有趣味的任务
会被善于沟通的人揽走。那些人可以推销自己的观点,擅长与客户沟通,知
道客户最需要什么。
2.2 计算机用于处理数据
上面讲述了编程人员的职责,下面来分析计算机的作用和特殊之处。
2.2.1 机器、计算机和人
人是能制造工具的动物。数千年来,我们发明了很多工具,让人类的生活变
得更加便利。最初发明了机械设备,如犁,提高了耕地效率。在 20 世纪,我们进
入了电子时代,并在 1946 年发明了计算机。
随着计算机体型变小,价格降低,计算机渗透到我们生活的各个方面。很多
设备(如手机)之所以能够工作,是因为我们将计算机嵌入其中。但要记住计算机
的作用:计算机用于自动完成以前需要人脑完成的操作。计算机谈不上绝顶聪明,
它只是按所给的指令做事罢了。
计算机处理数据的方式与香肠机绞肉的方式类似:从一端放入食料,执行一
些处理,从另一端输出香肠。可将程序比作教练在赛前给球员传达的指令。教练
可能说:“如果对方从左翼进攻,我希望 Jerry 和 Chris 回防;但如果对方传球,
我希望 Jerry 能够截断。”这样,开赛后,球员将按计划行事,从而击败对手。

不过,计算机程序与足球队员有一个重要的区别。如果教练的安排极其荒谬,
球员会发觉。如果教练说:“如果对方从左翼进攻,我希望 Jerry 高唱国歌的第一
段,然后疾速奔向出口”,那么球员将提出反对意见。
遗憾的是,程序并不知道它所处理的数据是否合理,就像香肠机不知道什么
是肉一样。即使将一辆自行车放入香肠机,机器也会设法造出香肠。即使将无意
义的数据输入计算机,计算机也会用这样的数据去做无意义的事情。在计算机看
来,数据就是传入的信号模式,必须遵循一定的方式对其进行处理,来生成另一
类信息模式。计算机程序是指令序列,告诉计算机如何处理输入数据,并确定输
出数据的形式。
下面列出典型的数据处理应用示例(可参见图 2-2):
● 手机——手机中的微型计算机从无线电波中获取信号,将信息转换为声
音。同时,它从麦克风获取信号,将其转换为位模式,通过无线电波传播
出去。
● 汽车——发动机中的微处理器从传感器那里获取信息, 即发动机当前的速
度、行驶速度、氧气占空气的百分比、加速器设置等。微处理器产生电压,
控制燃油喷射、火花塞的时长等设置来优化发动机性能。
● 游戏机——计算机从控制器那里收到指令, 使用这些指令来管理为用户创
建的虚拟世界。

图 2-2 设备中的计算机
当今制造的大多数较复杂设备都包含数据处理组件,来优化性能;当然,个
别设备包含此类组件或许只起锦上添花的作用。“物联网”的发展促使计算机渗透
到范围广泛的领域。必须认识到,数据处理不仅用于计算员工薪水——计算数字
并打印结果(这是传统的计算机使用方式)。作为软件工程师,我们难免要耗费大
量时间将数据处理组件安装到其他设备上来驱动它们。这些嵌入式系统意味着,
很多人在不知不觉地使用计算机!

专家点津
软件是生死攸关的
注意,似乎对人畜无害的程序可能危及人的性命。例如,医生可能使用你编
写的电子表格来计算病人的服药量。此时,如果软件存在缺陷,将对病人的
身体造成伤害。有关编程人员因疏忽导致重大灾难的详细描述,请在网上搜
索 Therac-25。
2.2.2 程序用于处理数据
图 2-3 显示了每台计算机所做的工作。输入数据到计算机,计算机处理数据,
并输出数据。我们来决定数据的组成以及输出的意义,程序也可做到这一点。

图 2-3 计算机用于处理数据
如上所述,也可将程序视为食谱,如图 2-4 所示。

图 2-4 食谱和程序
在本例中,厨师扮演着计算机角色,而食谱是程序,控制厨师使用配料的方
式。食谱中可使用许多不同的配料,程序也可以使用多种不同的输入。例如,程
序可能获得你的年龄以及你爱看的电影,并提供输出,基于合理的等级确定你能
否观看某部影片。
2.2.3 Python 用于处理数据
可将 Python 本身作为数据处理者(见图 2-5)。用 Python 编写的程序可传给
Python 引擎,然后 Python 引擎生成一些输出。

图 2-5 Python 用于处理数据
如上所述,有时输出是一个错误(例如前面输入 hello 时的情形),有时则是基
于 Python 语言的哲理语句(例如输入 import this)。让我们使用 Python 命令 shell 进
一步了解 Python 语言的工作原理。
与 Python 对话
上次我们与 Python 交流时,说的话很少。现在,我们要进行更深入的对话,
来进一步了解 Python 的工作原理。就像上一章中所做的那样,首先使用 IDLE 命
令来启动 Python Shell(见图 2-6):

图 2-6 启动 Python Shell
在第 1 章中, 我们想要问候 Python, 但效果不佳。 因此, 此次我们给命令 shell
提供计算机能理解的指令,可能是数字。输入数字 2,按下 Enter 键(见图 2-7):

图 2-7 输入数字 2,按下 Enter 键
这一次,屏幕上未显示错误消息,只是简单地回显了数字 2。看起来, Python
Shell 找到了答案并发送给我们。为验证这一点,给它提供一个求和表达式,例如
2+2(见图 2-8):

图 2-8 M 提供一个求和表达式
此时, Python Shell 未回显 2+2,它计算出结果并返回给我们。
看起来, Python Shell 收到我们的指令后执行了一些操作。实际上确实如此。
Python 的核心是一个表达式计算器,会自动计算结果。向 Python Shell 输入一个
表达式,它就会给出结果。图 2-9 显示了一个简单的表达式。

图 2-9 对这个简单表达式进行分析
表达式中的数字称为“运算数(operand)”, 完成实际工作的是运算符(operator)。
在表达式 2+2 中,有两个运算数(即两个 2),有一个运算符(加号)。为 Python Shell
提供一个表达式时, Python Shell 将区分运算符和运算数,并计算出结果。

错误的表达式
我们已经看到,如果输入 Python 不能理解的内容, Python 就提出抗议,显示
错误消息。如果给 Python 提供无效的表达式,结果同样如此(见图 2-10)。

图 2-10 给 Python 提供无效的表达式
编程人员输入表达式 2+,这是一个无效表达式, Python Shell 明显不满,显
示了一个红条和一条红色的错误消息。
Python 擅长处理表达式。如果愿意,你完全可用 Python 替代计算器。表达式
的计算方式与数学家计算数字的方式相同,括号的优先级最高,先计算乘法,再
计算加法。
可用 Python Shell 做一些计算表达式的实验。从现在起, 不再显示 Python Shell
的屏幕截图,只显示 IDLE 中的输出结果。也就是说,前面发出的三条 Python 命
令如下所示:
>>> 2
2
>>> 2+2
4
>>> 2+
SyntaxError: invalid syntax
输入的文本显示为黑色, Python 的输出显示为蓝色,命令提示显示为褐色,
错误消息显示为红色。
Python 表达式
本书穿插很多“代码分析”特殊段落,这些段落会针对上文的代码提示问题。
你可以先自行回答,然后阅读答案来强化理解。

问:如果尝试计算 2+3*4,会得到什么结果?
答: * (星号)是乘法运算符。 Python 用* 替代×(数学中的乘号)。始终在执行
加法运算前执行优先级更高的乘除运算,因此上述表达式的计算结果是 14。即先
计算 3*4,得到 12,然后加上值 2。如果在 IDLE 中尝试,将得到相同的结果:
>>> 2+3*4
14
问:如果尝试计算(2+3)*4,会得到什么结果?
答:将首先计算括号中的表达式。在上面的表达式中, (2+3)的结果是 5,然
后将 5 与 4 相乘,得到结果 20。
>>> (2+3)*4
20
问:如果尝试计算(2+3*4,会得到什么结果?
答: 这是个有趣的问题。 可在 Python Shell 中试一下。 Python 会自我思考:“这
个表达式不完整,需要加一个闭括号”。因此, Python Shell 会等待你继续输入。
如果你输入闭括号,就构成一个完整的表达式;此后将计算值并显示结果。也可
在第二行添加更多信息。
>>> (2+3*4
)
14
问:如果尝试计算)2+3*4,会得到什么结果?
答:如果 Python Shell 在看到开括号之前看到闭括号,就立即认定代码中存
在错误,于是显示一条错误消息:
>>> )2+3*4
SyntaxError: invalid syntax
注意,命令 shell 会突出显示不正确的字符,尝试帮助你找到错误的出处。
Python 是一门脚本语言
之所以可以像上面那样与 Python Shell 对话,是因为 Python 是一门脚本编程
语言。可将 Python Shell 视为 “
机器人演员 ”,执行你提供的任意 Python 命令。
换句话说,你使用 Python 语言告诉命令 shell 你要求程序做什么。如果“
机器人
演员
”听不懂你的指令,它就会诚实地反馈(通常显示红色文本)。
取出程序,然后执行其中指令的过程称为“解释程序”。演员通过表演台词来
谋生,计算机通过解释程序指令为我们解决问题。

专家点津
并非所有编程语言都像 Python 一样运行
并非所有编程语言都是“脚本”语言,只有脚本语言才会采用与 Python 同
样的解释方式。有时,程序指令会被转换为计算机硬件理解的极低级指令。
这个过程称为编译(compilation),执行此转换的程序称为编译器(compiler)。
经编译的指令此后加载到计算机中等待执行。因为执行的是经过编译的低级
指令,计算机不必分析指令的含义,只是遵照执行,因此该技术生成的程序
的运行速度极快。
你或许因此认定 Python 是运行缓慢的计算机语言,因为每次 Python 程序运
行时,“机器人演员”必须在执行每条命令前确定含义。但这并非真正的问
题,现代计算机的运行速度极快, Python 使用一些聪明的技巧在运行时编
译程序。
2.3 数据和信息
现在我们知道,计算机是处理数据的机器,程序告诉计算机如何处理数据。
下面进一步分析数据和信息的特性。人们交替使用单词“数据”和“信息”,但有
必要区分二者,因为计算机和人员以不同方式考虑数据。可分析图 2-11,其中显
示了差异。

图 2-11 数据和信息
图 2-11 中的两项包含相同的数据,只是左侧的图像更倾向于描述文档在计算
机中的存储方式。计算机使用数字值来代表文章中的每个字母和空格。如果你分
析每个值,可找到相应的文字;开头是值 87,它代表大写字母 W (位于右侧文档
第一段开头的 When 中)。
考虑到计算机存储数据的方式,在数字到字母的映射之下还有一层。计算机
中保存的每个数字都是 on 和 off 信号的独特模式(即 1 和 0)。在计算领域,每个 1
或 0 都称为位。 请参阅 Charles Petzold 撰写的优秀书籍
Code:The Hidden Language
of Computer Hardware and Software
,以了解计算机在此级别的操作方式,以及这
些如何构成所有编码的基础。意指大写字母 W 的数值 87 的存储方式如下:
1010111
这是数值 87 的二进制表示形式。由于篇幅所限,此处不精确描述工作原理
(Charles Petzold 已经描述了相关原理)。可将该位模式解释为: 87=1+2+4+16+64。
该模式中的每一位都告诉计算机硬件是否存在 2 的次方。如果对此不甚了解,
也不必过分担心,但要记住,就计算机而言,数据是由 1 和 0 组成的集合,计算
机存储和操纵这样的数据。
而“信息”是人对数据的解释。严格地讲,计算机处理数据,而人处理信息。
例如,计算机在内存某处存储以下位模式:
11111111 11111111 11111111 00000000
可将其理解为“你从银行卡透支$256”,或“你所在的位置比水平面低256英
尺”,或“32个照明开关中的8个关了”。通常在人们读取输入时,完成从数据到信
息的转换。再哆嗦一遍,计算机并不知道它处理的数据的含义。在计算机看来,
数据只是位模式;由用户为这些模式赋予意义。或许你的银行卡上实际只有$83,
而银行却声称你拥有$8388608,此时你将能更深刻地理解这一点。
1. Python 中的数据处理
我们知道, Python 用于处理数据。用 Python 编写的脚本由 Python 系统来解
释,此后生成一些输出。我们也知道,在运行 Python 程序的计算机中,数据值由
位模式表示(on 和 off)。
在 Python 中使用文本
让我们以 Python 能够理解的方式向 Python 问好。在 IDLE 中返回 Python Shell,
输入单词'hello',这一次,我们将 hello 用单引号括起来:
>>> 'hello'
'hello'
此次没有显示错误消息, Python 只是回显了我们输入的文本。将这与输入数
字时的行为进行对比,就会注意到, Python 事实上做的是同样的事情。上一次,
我们输入数字 2, Python 回显 2。此次输入文本值时, Python 回显了文本。前面
曾试图求两个数字的和;下面试着求两个文本字符串的和:
>>> 'hello' + ' world'
'hello world'
效果不错,Python 的行为完全合乎预期。我们知道,我们要 Python 求和,Python
就计算结果并返回。前面曾用这种方式求 2 和 2 的和。这里用同样的过程求'hello'
和' world'的和。注意,我非常明智地在单词 world 前加了一个空格;如果不加的
话,程序显示的结果将是'helloworld'。
Python 内部的处理也十分聪明,不管是数字还是字符串,它都能正确地处理
加法(+)。如果让 Python 求两个数字的和,它将返回数字。如果让 Python 将两个
字符串连接起来,它就十分顺从地将一个字符串连接到另一个字符串,返回一个
完整的字符串。
违反 Python 规则
问: 如果在输入字符串时漏了闭引号,会发生什么?
答: 根据前面漏了括号的经验判断,你可能认为 Python 会在下一行耐心等着
你给字符串输入闭引号。但实际上,事情不是这样。
>>> 'hello
SyntaxError: EOL while scanning string literal
“字符串字面量”是一个文本字符串。字母 EOL 是 End Of Line 的缩写。Python
Shell 消息的含义是: 不希望你在字符串中输入换行符。 Python 认为单个运算数(数
字或字符串)不能跨越多行。创建一个跨越多行的文本表达式是可以的(你可试一
下),但 Python 不允许表达式的运算数跨越多行。
问: 如果从一个字符串中减去一个字符串,会发生什么?
答: Python 非常聪明,能够分辨出来。因此,你完全可使用减号求两个数字
的差(你可以尝试一下);但不能从一个字符串减去另一个字符串。
>>> 'hello' - ' world'
Traceback (most recent call last):
File "", line 1, in
'hello' - ' world'
TypeError: unsupported operand type(s) for -: 'str' and 'str'
Python 详细解释了出错原因,没有说“减去字符串十分愚蠢”,却给出了较难
理解的描述信息。为此,需要了解到,“运算数”的含义是“运算符处理的内容”。
这里,运算符是减号(-),运算数是两个字符串(hello 和 world)。 Python 表明,你
不能在两个字符串之间放置减号。
问: 如果尝试将数字与字符串相加,会发生什么?
答: 与一个字符串减去另一个字符串一样,将数字与字符串相加是愚蠢的,
Python自然会显示错误消息,而且消息也很难理解。
>>> 'hello' + 2
Traceback (most recent call last):
File "", line 1, in
'hello' + 2
TypeError: must be str, not int
但愿此次消息更易于理解。 Python 消息指出:必须是字符串,不能是整数(这
种提示没有多大帮助作用,它并未告知究竟是哪里出错了)。
如果确实想将数字 2 放在单词'hello'的后面,可将该数字放在引号中:
>>> 'hello' + '2'
'hello2'
>>>
问: 如果尝试将数字与字符串相乘,会发生什么?
答: 确实可以,会将字符串重复给定的次数。
>>> 'hello' * 3
'hellohellohello'
Python 将尝试在能力范围内做一些明智的事情。如果交换运算数的顺序,这
个表达式依然有效。如果尝试将字符串与零或负数相乘, Python 仍将做一些有意
义的事情。
2. 文本和数值数据类型
如果仔细查看上述语句的结果, 将会注意到, 当 Python 计算数值表达式时(将
数值作为结果),它仅返回数值;但如果它对字符串求值,便返回包括在引号中的
文本,原因在于 Python 遵守有关各种数据的表达方式的规则。
Python 强制分离数值数据(值 2)和文本数据(字符串 hello)。对于不同数据类型,
值的存储方式和操作效果是不同的,即使为每种类型使用相同的运算符也同样如
此。可使用+运算符将数值或文本字符串相加, Python 会识别出操作上下文,确
保得到正确的结果。如果它看到加号位于两个数字之间,就使用数值版本的+。如
果看到加号位于两个字符串之间,就会使用字符串版本的+。
人们也在做同样的事情。当我们洗脸、洗盘子或清洗房间时,虽然动作都是

“洗”,但每种情况下的实际做法是不同的。如果用英语讲,三个动词都是 wash。
如果只写一个“洗”字,读者必须绞尽脑汁,探索会发生什么事情。当然,计
算机并不擅长“绞尽脑汁”和“探索”。因此,当我们编写程序时,必须用前后一
致的方式表达我们想做的事情。 Python 和其他编程语言的设计要求我们这样做。
2.4 使用 Python 函数
我们已经了解到 Python 处理文本和数值的方式,现在开始研究实际上如何用
数字(甚至是位模式)表示文本元素。为此,我们使用 Python 自身来探索它如何存
储值。我们使用 Python 语言内置的一些函数。函数(function)是具有不同名称的行
为。如果为演员写剧本,应加上舞台指导,如“左移”“望着窗外”或我喜欢的“逃
离虎穴”。演员将根据这些在舞台上完成动作。你将这些视为“函数”,演员一看
到,就知道如何去做。 Python 就像演员,它知道如何执行一组内置的函数。我们
将使用其中一些函数来研究文本在计算机中的表示方式。
专家点津
函数是任何编程语言的重要部分
学习编程语言的一个重要部分是学习它提供的函数。在后面的几章中,你将
学习一些函数,并开始编写自己的函数。
每个 Python 函数都有不同的名称,可能需要为其提供要处理的数据。在这方
面,可将函数视为微型数据处理器,你为函数提供数据,函数生成结果。
2.4.1 ord 函数
Python 知道如何执行的一个操作是 ord, ord 是 ordinal value 的简写。初看
ordinal,会感到有些困惑。在这个上下文中,它的意思是“将一系列字符中这个
字符的相应数值传给我”,或简言之,“给我提供表示这个字符的数值”。
调用函数时,会提供函数的名称,后跟函数使用的数据(放在小括号中)。
图 2-12 分析了 ord 函数的调用。“给函数提供的数据”的程序名是参数。

图 2-12 分析函数调用
使用 ord 函数研究文本的表示方式
使用 ord 函数研究计算机中存储文本的方式。首先找到用于表示特定字符的
数值。为 ord 函数提供一个字符串,其中只包含一个 W 字符,看看会显示哪个数
值。在 IDLE 中,给 Python Shell 输入命令,注意返回的结果。
>>> ord('W')
87
这正是在图 2-12 中看到的结果。 题目为 Declaration of Independence 一文第一
段的第一个字母 W 对应的值是 87。
但在编写 Python 表达式时需要十分小心。我们感兴趣的 W 必须是文本字符
串的一部分,必须包含在单引号中。如果漏了单引号, Python 系统便认为我们想
了解有关 W 事物的信息,并告知它对 W 事物一无所知。
>>> ord(W)
Traceback (most recent call last):
File "", line 1, in
ord(W)
NameError: name 'W' is not defined
Python 程序中不经常使用 ord 函数,但该函数确实提供了一个十分有用的窗
口,使我们能了解到 Python 代码操纵的值。
2.4.2 chr 函数
ord 函数的一个 Python 补充函数是 chr。 chr 函数接受一个数值参数,并返回
该数值表示的字符。
使用 chr 函数将数值转换为文本
如果给 chr 函数提供值 87,并没有什么实际意义,但我们可以尝试一下。
>>> chr(87)
'W'
表示字符的数值按合理的方式排列, 这样, 如果想要显示与值 88 对应的字符,
你将得到预期的结果:
>>> chr(88)
'X'
在计算机领域,国际标准将特定值映射到特定字符。我编写计算机程序已经
很多年了,根据我的经验,我了解到字母 A 由值 65 表示,而空格字母(空格很重
要,可用它在文字中间加上空距)由值 32 表示。但通常不需要记住这些数字,因
为 Python 及支持的操作系统将负责显示文本。我也发现,即使了解这些数值,一
起参加聚会的人也对此提不起兴趣。
2.4.3 使用 bin 函数探索数据存储
可将计算机内存看作一长串小箱子,每个小箱子都有一个唯一的数值地
址。每个内存地址由 8 位组成(on 或 off,如前所述)。此类内存地址称为字节。
如果你的计算机有 16GB 内存,那么地址数量就是 16G,每个地址的大小是一个
字节。
单个字节不能存储范围很大的值,因此将多个字节组合在一起来存储更大的
数值。后面将讲述其工作原理,还将讨论 Python 可存储的值,此处分析用于存储
值的位模式。
Python 内置的 bin 函数接受一个数值,并返回表示该数值的位串。
确定二进制表示形式
可使用 bin 函数来探究如何在计算机中存储数据。
>>> bin(87)
'0b1010111'
bin 函数返回一个字符串,该字符串是相应数值的二进制表示形式。注意,这
个字符串由 0 和 1 组成。字符串开头的 0b 告诉读者:这是数值的二进制表示形式。
构建二进制数
在 Python 程序中, bin 函数的使用频率不高(除非有一个特殊客户,要求你编
写程序来显示二进制值),但我们可使用该函数来研究数值在计算机中的存储方
式。记住,在计算机硬件中,所有数据都用特定信号的高低电平来操纵,可认为
0 是零电平, 1 是某一电平。
问: 0 的二进制值是什么?
答: 为回答这个问题,也可以使用 bin 函数。
>>> bin(0)
'0b0'
0 值的二进制值还是 。
问: 1的二进制值是什么?
答: 为回答这个问题,也可以使用bin函数,将1作为参数。
>>> bin(1)
'0b1'
1 的二进制值还是 1。迄今来看,二进制值并无特别之处。
问: 2 的二进制值是什么?
答: 为回答这个问题,也可以使用 bin 函数,将 2 作为参数。
>>> bin(2)
'0b10'
情况发生了变化。要了解原因,首先考虑十进制数 10,其中的 1 表示该数值
有几个 10。二进制数的原理是一样的,只是此时的 1 告知该数值中有多少个 2;
因此,二进制值 10 表示 2。
问: 二进制值 11 表示多少?
答: 我认为,二进制值 11 是十进制值 3(2+1),可使用 bin 函数对此进行测试。
>>> bin(3)
'0b11'
从右数第 3 位的 1 是数字 4,第 4 位的 1 是 8,依此类推。你可能想用 bin 函
数来核实数值的位模式,然后检查结果。
问: 二进制值 86 与二进制值 87 的差别是什么?
答: 可使用 bin 函数对此进行测试。
>>> bin(86)
'0b1010110'
>>> bin(87)
'0b1010111'
比较这两个二进制模式可看到,最右侧的位从 1 变为 ,因为这一位表
示二进制值包含 1。最右侧包含 1 的数值都是奇数。如果不信,你可以多试
几个值。
2.5 本章小结
本章学习了计算机的实际工作原理以及程序的作用。从中了解到,计算机将
整个世界视为 on 和 off 模式, 该模式表示计算机处理的数据。 计算机处理数据时,
将一种位模式(输入)转换为另一种位模式(输出)。
当人们看到输出数据并对其执行操作时,数据就变成信息。计算机并不能像

人类那样理解所处理的位模式的含义,这意味着,计算机可能以愚蠢的方式处理
数据。
程序告诉计算机如何处理位模式。计算机自身只理解简单指令,指令必须用
特殊语言(即编程语言)写成。 Python 是一门编程语言,作为计算机程序运行,它
接收程序指令并按照指令进行操作,就像演员根据剧本表演一样。
编程人员负责将程序创建为一系列指令,这些指令描述要执行的任务。要创
建成功的解决方案,编程人员不仅要编写优秀的程序,还要确保程序真正能完成
用户要求的任务。这意味着,在编程人员编写任何代码之前,务必准确了解用户
需求。与其他人交流,从而了解他们需要什么;要成为一名成功的编程人员,这
是一项十分重要的必备技能。
为加深对本章知识点的理解,请思考以下有关计算机、程序和编程的“深奥”
问题:
对于像“某人的年龄是–20 岁”这样的说法,计算机会觉得十分愚蠢吗?
不会。在计算机看来,年龄值就是一个表示数值的位模式。如果想让计算机
抛弃负数年龄,你必须将这样的思想构建到程序中。
如果为汽车的注油系统设置程序输出,输出的是数据还是信息?
一旦开始根据数据采取行动,数据就成为信息。司机不使用这些值做什么,
但这些值将改变发动机的速度,这又会影响人员。因此说,这种输出是信息而
非数据。
计算机不懂英语,所以说计算机很笨,是这样吗?
用英语写成的句子很难做到完全没有歧义。律师的主要工作就是精确解释文
字的含义,并解释文字在特定情形中的使用方式。人类都不能对某句话的理解达
成一致,因此不能强求计算机正确无误地理解,不能就此认为计算机很笨。
如果不知道如何解决某个问题,能为其编写程序吗?
不能。你能将一些语句堆砌在一起,看看运行时会发生什么,但不大可能得
到你要的效果。这就像某人喜欢将一堆车轮、齿轮和引擎扔到墙根下,巴望着它
们完美结合在一起,形成一辆能跑的汽车。事实上,编写程序时,最好经常离开
键盘,想一想究竟要用程序完成什么任务。
主观认为客户将“英寸”作为所有物品的尺寸度量单位是明智的想法吗?
对项目做任何无端的臆测都是不明智的。一名成功的编程人员必须确保自己
所做的一切都建立在深入了解的基础之上。你做的任何臆测都会增加发生灾难的
可能性。
如果程序做了错事,是我的责任还是客户的责任?

32 第 I 部分 编程基础知识
回答这个问题具体取决于:
● 规范正确,程序错误:编程人员负责
● 规范错误,程序正确:客户负责
● 规范错误,程序错误:双方担责

Python 程序用作网络客户端
本章主要内容
本章将介绍如何创建与 Internet 和万维网交互的 Python 程序,将介绍计算机
网络的基础知识,讲述如何创建可从
Internet Web 服务器获取信息的程序,分
析用于在程序之间传递数据的标准。
14.1 计算机网络
在学习 Python 程序如何使用网络连接前,需要了解一些有关网络的知识。本
章对网络知识不做详细解释,只呈现一些背景知识,帮助你了解程序的工作方式。
1. 网络通信
网络使用网线、无线设备或光纤连接来发送数据信号。无论哪种介质,基本
原理都是:硬件将数据以“数字位”格式放在介质上,此后重新获取数据。位是
0 或 1(也可将位视为 True 或 False),可通过电平高低、发光二级管(LED)的光、无
线信号来传递。设想一下,你可通过开关卧室的灯(如图 14-1),与住在马路对

图 14-1 “房间-房间”网络
14
面房子里的友人通信;这就是网络通信的起点。
一旦你拥有将信号从一个地方发送给另一个地方的基本能力,就可以开始传
输有用的数据。我们可发明一个协议(消息和响应的排列方式),并依据协议来传
递消息。要传递有用的信号,必须就消息格式达成一致意见。你可以说:“如果我
家灯灭,再闪烁两次,则意味着我姐出去了,你可到我家来;如果闪烁一次,则
你不要过来;如果闪烁三次,你过来时带上比萨”。这就是协议基础,通信各方就
消息的构建和含义取得一致,来达成协议。
消息和协议相互独立。我们可用“敲击水管”或“喷出烟雾”来替代“灯光
闪烁”,协议都是一样的。三次闪烁或三次敲击的意思都是“带比萨过来”。设计
网络时,可使用层来表示,如图 14-2 所示。

图 14-2 网络中的层
物理层传递网络事件,协议位于物理层之上。我们可通过灯光闪烁、敲击水
管或喷出烟雾来传递网络消息。每一层都会建立标准。例如,网络中的“灯光”
物理层的标准将是“一次闪烁时长不超过 0.5 秒,所有闪烁时长不超过 5 秒”。而
“管道”层的标准将描述敲击的最小响度。
物理层之上的传输层不考虑消息的传递方式,它只了解已经接收了什么消息
事件。可添加新的消息传递方式。例如,可在不更改整个网络的情况下,添加“摆
旗”传递方式。 Internet 使用的网络协议基于这种分层方法。
2. 地址消息
如果有两位朋友与你住在同一街道,你们想通过卧室灯光通信系统来传递信
息,那么,该系统将变得更复杂。你必须添加一些地址形式,并指出每个人在网
络中的唯一地址。现在,消息由两部分组成。第一部分是接收方的地址,第二部
分可能包含消息本身。计算机网络的工作方式与此类似。物理网络的每个部分都
必须具有唯一地址。发送到某站地址的消息将由该站中的网络硬件接收。
网络还有广播地址,允许一个系统向每个系统发送消息。在“卧室灯光网络”
中,可使用广播地址来通知两位朋友,你的姐姐已经回家,带回来新交的男友,
因此你家不能再招待其他客人。在计算机网络上,通过广播,可使新计算机了解
网络中重要系统的地址。一个系统可发送广播消息:“各位好,我是新来者”,另
一系统可能响应,响应中包含配置信息。
网络中的所有工作站都可以接收和处理广播消息。事实上,如有必要,工作
站可侦听在网线或 Wi-Fi 通道上传送的所有消息,这当然是个网络问题。就像所

有朋友(以及其他局外人)都可以看到卧室灯光表达的所有消息一样,无法阻止有
人偷听网络上流动的信息。当连接到安全网络时,计算机将对发送的所有消息进
行编码,这样,除了预定的接收者之外,侦听消息的其他人将一无所获。
3. 主机和端口
如果想使用卧室灯光闪烁协议与住在同一地址的人员交流信息,我们需要改
进协议。如果要给 Chris 和 Imogen 发送消息,这两个人住在同一房间。我们需要
改进协议,使包含数据的消息可以确定接收者。
在计算机系统中,存在同样的问题。一个给定的计算机服务器可以给与其连
接的多个客户机提供大量不同的服务。服务器可能给一个用户发送网页,给另一
个用户发送视频,同时支持 20 个玩家使用的多人游戏。不同客户端需要通过一种
方式,找到它们想从服务器获得的服务。
Internet 通过使用“端口”达到这个目的。端口是一个编号,用于确定计算机
提供的服务。一些端口“人所共知”;例如端口 80 在传统上用于网页。换句话说,
当浏览器连接到网页时,它在使用服务器的 Internet 地址找到实际计算机,然后
连接到该计算机的端口 80 来获得网页。
程序启动服务时,会将服务所在的端口告知网络软件。当消息到达相应端口
时,将消息传递给程序。可以这样想, Internet 使一个程序可与远程计算机上的另
一个程序交流。目标程序(可能是 Web 服务器)可能位于与 Internet 连接的计算机的
一个端口之后。你运行另一个程序(可能是 Web 浏览器)创建与该端口的连接,这
样一来,将可以请求网页,并将网页的内容显示在计算机上。
编程人员所写的程序可使用任意端口号,但很多网络连接包含一个称为“防
火墙”的组件,防火墙只允许目标地址是广为人知的特定端口的数据包通过;这
可降低网络系统受到恶意网络程序攻击的可能性。
4. 使用 Python 发送网络消息
上面讲述了网络的基本工作原理,现在分析 Python 程序如何使用网络来发送
和接收消息。我们将使用 Internet 协议套件中的 UDP(User Datagram Protocol,用
户数据报协议)来发送消息。
发送网络消息
要学习网络知识,最好执行操作,将消息从一个程序发送到另一个程序。可
在 IDLE中从 Python Command Shell执行此操作。首先启动 Python Command Shell,
导入 socket 模块中的所有资源。输入以下命令并按 Enter 键:
>>> import socket
socket 模块包含 socket 类, socket 类用于创建和管理网络连接。首先创建一
个用于接收消息的 socket 类实例。输入以下语句并按 Enter 键:
>>> listen_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
socket 构造函数接受两个参数。第一个是用于指向主机的地址族,这里将使
用 Internet 地址族,因此使用 socket 模块的 AF_INET 值。第二个参数是要发送的
消息的类型。我们将发送数据报(datagram)。数据报是一个未经确认的消息,从一
个系统发送到另一个系统,这与“房屋-房屋”网络通过灯光闪烁将消息发送给其
他人(包括正在观看者和未观看者)是一样的。
现在创建套接字,我们需要考虑将连接到的地址。可将网络地址写成一个元
组。输入以下语句并按 Enter 键:
>>> listen_address = ( 'localhost' , 10001)
数据报是从一个系统发送给另一个系统的消息。除非接收者返回确认消息,
否则数据报的发送者无法确定消息是否已被接收。 Internet 协议套件是一组标准,
通常称为 TCP/IP 套件,用于描述 Internet 和相关网络的工作方式。该标准最初用
于描述传输控制协议(Transmission Control Protocol, TCP)和 Internet 协议(Internet
Protocol, IP); TCP 连接网络上的系统, IP 允许在网络之间通信。可访问 https:/
/en.wikipedia.org/wiki/User_Datagram_Protocol 来很好地了解 UDP 的工作方式。
listen_address 元组包含两个值。第一个值是要连接到的计算机的地址。最初,
只需要将消息发送给自己的计算机上的一个进程,因此使用特殊地址′localhost′来
表示当前计算机。元组的第二个值是程序将要连接到的端口。使用编号(这里使用
10001)来识别端口。
接下来需要将套接字绑定到将要侦听的服务器地址。此后,套接字将可侦听
地址中给出的端口上的消息。 bind 方法给出要侦听的地址,并配置套接字侦听给
定地址。输入以下命令并按 Enter 键:
>>> listen_socket.bind(listen_address)
现在要求套接字接收一些数据。为此可使用 recvfrom 方法, recvfrom 将获取
单个数据报。它接受一个参数,参数给出将接受的数据报的最大大小。输入以下
命令并按 Enter 键。
>>> result = listen_socket.recvfrom(4096)
注意,命令窗口未返回>>>提示符,原因是 recvfrom 方法尚未返回结果;它
正在等待数据报的到达。
现在需要制作传输器。为此,需要启动另一个 IDLE Python Command Shell
副本。与侦听程序一样,首先需要导入 socket 模块:

>>> import socket
现在制作发送套接字。输入以下语句并按Enter键。
>>> send_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
注意, send_socket 的创建方式与 listen_socket 相同。接下来需要创建地址,
来识别消息的接收者。我们将给自己发送消息,因此使用同一地址。输入以下语
句并按 Enter 键。
>>> listen_address = ( 'localhost' , 10001)
最后,通过网络发送消息。输入以下语句:
>>> send_socket.sendto( b'hello from me' , send_address)
这样, 将从 IDLE Command Shell 将消息发送到端口 1001 中列出的侦听程序。
按下 Enter 键发送消息:
>>> send_socket.sendto( b'hello from me' , send_address)
13
>>>
sendto 方法返回已发送的数据字节数;此处发送了 13 个字节(字符串 hello
from me 中的字符数)。你可能会问,为什么在这个字符串的前面加上字母 b?原
因在于, Python 3 通常使用 Unicode 标准对字符串字符进行编码。我们无法通过
套接字发送 Unicode 值, 但可发送字节。 将字母 b 放在字符串前面, 可告诉 Python
从字节(byte)而非 Unicode 字符获取相应的字符串。这样就发送了消息,下面来看
收到的内容。
返回正在运行侦听器的 IDLE Command Shell。可以看到, >>>提示符已经返
回,因为 recvfrom 方法已经完成,并返回变量 result 中的值。可使用 print 函数查
看结果:
>>> print(result)
当按下 Enter 键执行 print 时,将看到 result 的内容是一个元组,元组中包含
两个条目。第一个条目是一个字符串,其中包含发送者发送的消息。第二个条目
是另一个元组,包含发送消息的系统的地址。下一个练习将使用这些函数在计算
机之间发送消息,其中将讨论 Internet 地址。
>>> print(result)
(b'hello from me', ('127.0.0.1', 51883))
这些操作是使用 Internet 的每个程序的基本构件。每当你加载网页、观看视
频或发送电子邮件时,传输数据的方式都是一个进程侦听数据包,另一个进程发

送数据包。
发送网络消息
下面是一些你需要思考的问题。
问: 可发送除文本外的其他信息吗?
答: 可以。数据报发送字节值块,其中可以包含任何类型的数据。上面传输
了字符串,但你同样可以方便地传输时装店库存商品条目。
问: 最大可发送多大的数据?
答: 可在 recvfrom 方法中设置传入消息的最大大小。程序可发送包含大约
65 000 字节的消息。如果发送更大消息,则必须分成多个消息来发送。幸运的是,
还有其他网络函数可以分离和组合更大的条目。见本章后面的介绍。
问: 如果发送了消息,但侦听器未侦听到,会发生什么情况?
答: 什么都不会发生。我们正在发送最简单的消息类型,即数据报。发送方
无法了解数据报是否已被接收。
问: 侦听器可侦听来自另一台计算机的消息吗?
答: 可以。只要消息从正确的端口(此处是端口 10001)发出,侦听器将可以侦
听到。
问: 发送方可将消息发送给其他计算机吗?
答: 可以。通过使用不同的发送地址,套接字可将消息发送给其他端口和其
他计算机。
问: 侦听器等候多长时间才能侦听到消息?
答: 可能是永久等待。不过, Socket 模块提供了 setdefaulttimeout 方法,该方
法设置 recvfrom 对传入消息的等待秒数。如果到时前没有到达的消息, recfrom 方
法将抛出异常。
问: 使用套接字可生成异常吗?
答: 可以。在网络连接失败或主机意外断开连接时,使用网络连接的程序应
当捕获抛出的异常。
5. 将消息发送到另一台计算机
sendto 和 recvfrom 方法可用于通过本地网络将消息发送给另一台计算机。可
用这两个方法来连接家中的两台计算机。为此,需要获取接收消息的计算机的 IP
地址。可将这个 IP 地址看成计算机在网络上的“电话号码”。如果计算机没有 IP
地址,就无法给它发送消息。 Python 的 socket 模块包含多个函数,可用于查找运
行 Python 程序的计算机的 IP 地址。如果加载以下程序,将显示所在计算机的地
址。此后,将可在发送程序中使用相应的地址。

# EG14-01 Receive packets on port 10001 from another machine
import socket
host_name = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
print('The IP address of this computer is:', host_ip)
listen_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
listen_address = (host_ip, 10001)
listen_socket.bind(listen_address)
print('Listening:')
while(True):
reply = listen_socket.recvfrom(4096)
print(reply)
运行上面的接收程序时,它将显示消息,给出 IP 地址,然后说明它正在侦听
输入:
The IP address of this computer is: 192.168.1.55
Listening:
现在可加载准备传输数据的计算机上的发送程序。
# EG14-02 Send packets on port 10001 to another machine
import socket
import time
# You will need to change this to the address
# of the machine to which you are sending
target_ip = '192.168.1.55'
send_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
destination_address = (target_ip, 10001)
while(True):
print('Sending:')
send_socket.sendto(b'hello from me', destination_address)
time.sleep(2)
需要将程序中的 target_ip 值改为接收程序显示的地址。运行发送程序时,接
收计算机的屏幕上将显示消息。可按下 Ctrl+C 键或从 IDLE 菜单中选择 Shell |
Interrupt Execution 中止操作。
导入 socket 模块
将使用
time 模块的 sleep 函数
设置接收消息的计算机的
IP 地址
创建
socket
设置目标地址
永久循环
显示消息
发送消息
休眠
2 秒钟
导入
socket
获取计算机的主机名
使用主机名获取
IP 地址
显示
IP 地址
创建侦听器套接字
创建侦听计算机的地址
socket 与地址绑定
永久循环
等待传入的消息
显示消息

6. 路由数据包
我用上述示例程序完成了操作,因为两台计算机都连接到我的家庭网络。但
在 Internet 上,并非所有计算机都连接到同一网络。我的家庭网络与邻居家的网
络是不同的。 Internet 将大量不同的“本地”网络连接起来。要将消息从一个网络
传到另一个网络,必须使用“路由(routing)”方式。
回头分析“房间-房间”灯光闪烁网络,一位朋友住在大街很远处,可能无法
看到你家的灯光;但她可看到她邻居家的灯光。因此,可要求这位邻居接收消息,
然后代你将消息发给你的朋友。这位邻居可读取传入的消息的地址,如果目的地
是你的朋友,邻居将再次传输消息。图 14-3 显示了工作原理。朋友使用左侧窗口
与你交流,使用右侧窗口将消息传递给住在远处的朋友。
你家 朋友邻居家 远处的朋友家

图 14-3 借助另一个房间实现路由
可认为中间的邻居家在扮演路由角色。她可连接到两个网络:邻居可看到你,
朋友可看到邻居。邻居所处的位置使她可从一个网络接收消息,然后将消息重新
发送到另一个网络。与 Internet 的连接由路由器来管理,路由器是一台计算机,
专门用于使用 Internet 协议发送和接收消息。
图 14-4 显示了组合方式。家庭网络中的计算机直接连接。桌面 PC 可直接给
打印机发送消息。但是,如果桌面 PC 需要从 Microsoft 的 Web server 下载网页,
则页面请求必须离开本地网络,通过 Internet 来传递。离开本地网络的消息发送
给路由器,路由器将消息转发给 Internet。路由器还负责接收从 Internet 发往本地
网络的消息。路由器将这些消息重新传输给本地网络,找到正确的计算机。这个
过程称为网络地址转换(Network Address Translation, NAT)。

图 14-4 路由和 Internet
网络和防火墙问题
我设法使用示例程序 EG14-01 Receive packets on port 10001 from another
machine 和 EG14-02 Send packets on port 10001 to another machine,将消息从
Windows PC 发送到 Apple Mac。 Windows 防火墙要求我确认是否允许 Python 程
序使用网络,我确认后,程序开始正常工作。
防火墙是连接到网络的计算机中的网络管理软件的组件。它尝试确保程序以
正确方式使用网络连接。如果计算机感染了病毒,防火墙将阻止病毒程序使用网
络连接来感染其他计算机。防火墙保留了一个列表,其中列出有权使用网络的程
序。如果防火墙检测到前所未见的程序正在访问网络,它将要求用户确认是否允
许新程序使用网络,如图 14-5 所示。

图 14-5 要求用户确认是否允许新程序使用网络
选择上述对话框中的 Allow access 后,网络对话开始正常进行。但是,更难
将消息从 Mac 发送到 PC。如果这些程序不工作,原因可能是网络将程序限制到
一组特定端口上。如果两台计算机位于不同网络,这些程序也将无法工作。
7. 连接和数据报
Internet 为系统提供了两种交换信息的方式:连接和数据报。数据报是从一个
系统发往另一个系统的一条消息。前面创建的 Python 程序使用数据报。但是,你
也可使用 Internet 来创建网络上系统之间的连接。Internet 使用 TCP 来设置和管理
工作站之间的连接。可访问 https://en.wikipedia.org/wiki/Transmission_Control_
Protocol 来详细了解 TCP。
当两个系统连接时,它们必须完成一些额外工作来自行管理连接。如果一个
系统在连接期间发送消息,网络要么确认消息被成功传输(即网络收到确认消息),

要么显示一条错误消息,指出无法传输。如果必须确保传递整个消息,将使用“连
接”方式。
浏览器加载网页时,计算机和 Web 服务器共享网络连接,确保传递网页的所
有部分,并重传失败的部分。传输、确认和再次确认过程意味着数据传输速度变
慢。管理连接给参与通信的系统增加了负担。对于与另一台计算机的连接,可认
为其类似于将程序连接到文件的 file 对象。程序可调用连接上的方法,向连接发
送消息,并检查是否从连接接收到数据。连接将一直打开,直到使用连接的一个
系统将其关闭为止。
8. 网络和地址
使用上述测试程序来发送和接收消息时,我们使用了诸如 192.168.1.55 的地
址。 前面介绍过, 这称为 IP 地址, 可将它们视为网络上特定计算机的“电话号码”。
但谁也不愿意去记这样的 IP 地址。人们更愿意使用诸如 www.robmiles.com
的名称来查找网站。为解决这个问题, Internet 上的计算机将连接到名称服务器,
名称服务器将主机名转换为 IP 地址。后台系统称为域名系统(Domain Name
System, DNS)。 DNS 是一组服务器,负责在自身内部传递名称请求,直至找到具
有一组特定地址的相关系统,将名称与所需地址匹配。
可将名称服务器看成计算机的“查号台”。过去,如果我想了解本地影院的电
话号码, 我将致电查号台。如果计算机想要了解网站的 IP 地址, 将需要查询 DNS。
14.2 从 Python 使用 Web
Web 是使用 Internet 的服务之一。浏览器读取网页时,将设置与服务器的连
接,并请求页面内容。页面内容用 HTML(Hypertext Markup Language,超文本标
记语言)来表示。页面内容可能包括图像和音频引用, 图像和音频是网页的一部分。
浏览器将设置连接,下载这些内容,在屏幕上自动渲染网页。
14.2.1 读取网页
如果愿意,你可编写基于套接字的低级代码,来设置与 Web 服务器的 TCP
连接,并取回数据。但由于这十分常用, Python 的创建者已经替我们完成了这项
工作。 urllib 模块使用 Internet 连接与 Web 服务器通信,并获取网页。 URL 返回与
其关联的网页。
# EG14-03 Webpage reader
import urllib.request
url = 'https://www.robmiles.com'
导入 URL 读取模块
这是程序将要读取的
URL
req = urllib.request.urlopen(url)
for line in req:
print(line)
如果运行上述程序,它将显示我博客页面的当前内容,其中的内容可不少。
urlopen 对象使用 HTTP 请求网页,然后返回一个可供遍历的迭代器。
14.2.2 使用基于 Web 的数据
借助从 Web 读取内容的能力,不仅能加载网页文本,也可与其他很多数据服
务交互。其中一个服务是 RSS(Really Simple Syndication 或 Rich Site Summary),
这是一个描述 Web 文章或博客帖子的格式。很多网站都提供内容的 RSS 源,程序
可连接到 RSS 源,使用其中的内容。
使用上面的网页读取程序访问 https://www.robmiles.com/journal/rss.xml 来下
载文档,文档中包括我的最新博客帖子。文档使用 XML 标准格式。
第 5 章使用的天气 snaps 也从 Web 服务器获取天气信息。该程序从服务器下
载天气信息(格式是 XML 文档)。
1. XML 文档标准
XML 标准允许我们创建包含结构化数据的文档。文档便于计算机和人员读取。
编程人员创建 XML 文档将数据从一台计算机发送到另一台计算机。 XML 文档包含
大量元素。每个元素都有特性,此类特性与 Python 类的数据特性类似。一个元素
可以包含其他元素。有关 XML 的完整描述,请参阅 https://en.wikipedia.org/wiki/XML。
可使用从我的博客 RSS 源返回的 XML 文档来分析 XML 的工作方式,如下
所示。我删除了一些元素,但仍显示了文档的一般格式(实际上,我对自己的博客
甚感满意)。


<br/> robmiles.com <br/>

<br/> Water Meter Day <br/>
Life




文档中的 rss 元素
rss 元素中的 channel 元素
channel 元素的 title 元素
item 到此结束
博客帖子的种类
博客帖子的内容
title 文本
title 元素到此结束
博客中的
item
item
的标题
创建
Web 请求对象
遍历
Web 请求,每次一行
显示行


<br/> Python now in Visual Studio 2017 <br/>
Python
Visual Studio






将 XML 文档组织为元素。元素具有名称,可包含特性(有关元素的数据,与
Python 类特性类似)。上述示例中的第一个元素是 rss, rss 元素包含一个特性
version, version 特性指出元素包含的 RSS 版本。这与在 Contacts 管理程序中为
Contact 类添加的 version 特性是一样的。它将 RSS 元素的版本告知程序;在我的
博客中, version 是 2.0。

一个元素可包含其他元素,包含在之间。在上面可看到,
channel 元素包含两个 item 元素,每个 item 元素又包含 title 和 description 元素。
XML 文档格式
有关 XML 格式,你需要思考以下问题。
问: XML 中的父元素和子元素如何使用?
答: 一个给定的 XML 元素可包含其他元素,这称为子元素。子元素也可包
含其他子元素。在上面的 RSS 示例中, channel 元素包含两个 item 子元素。每个
item 都有子元素 title 和 description。
不要将子元素与超类的子类混淆。子类用在类层次结构中,继承超类(也称父
类)的所有特性。使用子类,可以定制超类,以更贴合具体情形。这些与 XML 文
档无关。
最好将 XML 子元素假想为元素的特性(就像是有关元素的数据片段), 但实际
上它是另一个 XML 元素。
问: CDATA 的含义是什么?
答: 将字符串放入 Python 程序,可为它们添加三引号(''')。三引号中的文本可
以跨越多个源程序行,可包含任何引号字符。 XML 文档中的 CDATA 元素的工作
方式与此类似。 之间的所有内容都被视为元素的文本。这样,可
将整个博客帖子放在 XML 文档的一个元素中。
博客帖子的种类
博客帖子的种类
item 到此结束
channel 到此结束
rss 到此结束
item 由此开始
问: 为什么文档中的第二个 item 包含两个 category 元素?
答: XML 未对 XML 文档中的内容或组织方式施加强制标准(不过,你可为此
使用 schema,但本书不予讨论)。可访问 http://www.xml.com/pub/a/2000/11/29/
schemas/part1.html 来进一步了解 XML schema。
可回顾第 11 章创建的时装店应用程序中使用的标签, item 的 category 元素与
其类似。读者可在我的所有博客中搜索有关 Python、 Visual Studio 或生活方面的
内容。 RSS 标准允许编写者根据需要使用足够多的 category 元素为 item 添加标签。
2. Python ElementTree
可编写程序来解码 XML 文件,但这是一项艰巨的工作。幸运的是, Python
提供 ElementTree 类,该类可用于 XML 文档。程序可在 ElementTree 实例中加载
一个 XML 文档,然后调用实例上的方法在文档中导航。
# EG14-04 Python ElementTree
import xml.etree.ElementTree as ElementTree
rss_text = '''

Sample RSS above goes here

'''
doc = ElementTree.fromstring(rss_text)
for item in doc.iter('item'):
title = item.find('title').text
print(title.strip())
description = item.find('description').text
print(' ',description.strip())
ElementTree 类提供了一系列方法,可用于查找和处理 XML 文档中的元素。
为 iter 方法提供元素名,将生成可用 for 循环遍历的迭代。 find 方法将在给定元素
中搜索具有特定名称的子元素。元素的 text 特性是元素的实际文本载荷。程序的
输出如下所示:
Water Meter Day
We had a new water meter installed yay!
Python now in Visual Studio 2017
Python is now available in Visual Studio 2017 yay!
你可使用很多方法来处理 XML 文档, 甚至可使用 ElementTree 类来编辑元素
内容、删除元素或添加新元素。你可使用上述方法从 Internet 的 XML 源提取数据
RSS 字符串创建一个 ElementTree 实例
导入模块并指定名称
迭代文档中的所有
item 元素
找到
item 中的 title 元素,从中获取文本
删除
title 文本中的多余空格并显示
找到
item 中的 description
元素,从中获取文本
删除
description 中的多余空格并显示
示例程序包含
XML 示例中的所有文本 项。示例程序 EG14-05 RSS Feed reader 包含一些可着手使用的内容。
使用天气数据
第 5 章中使用的天气 snaps 解码 U.S. Weather Service 的 XML 文档。可使用以
下代码获取给定位置的温度。
# EG14-06 Weather Feed Reader
def get_weather_temp(latitude,longitude):
address = 'http://forecast.weather.gov/MapClick.php'
query = '?lat={0}&lon={1}&unit=0&lg=english&FcstType=dwml'.\
format(latitude,longitude)
req=urllib.request.urlopen(address+query)
page=req.read()
doc=xml.etree.ElementTree.fromstring(page)
for d in doc.iter('temperature'):
if d.get('type') == 'apparent':
text_temp_value = d.find('value').text
return int(text_temp_value)
可在本章示例程序中的 EG14-06 Weather Feed Reader 文件夹中找到上面的函
数以及服务器返回的示例天气文件。尝试更改方法,以获取最高气温和最低气温,
并预测气温。
14.3 本章小结
本章介绍网络编程的基本原理,以及网络如何将数据从一台计算机传给另一
台计算机。可以看到,协议描述系统的通信方式, Internet 使用协议来描述不同功
能层,硬件位于底部,软件界面位于顶部。计算机之间以数据报形式传输信息,
在本地网络上,每台计算机都有唯一的 IP 地址。
可认为 Internet 由大量本地网络连接而成。名为“路由器”的设备将获取要
发送到远程站点(未与本地网络连接的计算机)的数据报,然后将它们发送到
Internet。网络连接有两种形式,一种是不予确认的单独数据报,一种是连接。一
个给定系统可在多个不同端口中的一个上公开连接。程序要接受连接时,会将软
件套接字绑定到主机上的端口,并接受相应端口上的连接。
通过传输大量数据报来传输大量数据。 Python 提供一个 socket 类来控制网络
天气 Web 服务器
Web 查询包含经度和纬度
构建
Web 请求
从网站读取文本
从文本创建
ElementTree
遍历所有 temperature 元素
相应元素的
type 特性是不是 apparent
获取
value 元素的内容,
value temperature
的子元素
返回从
value 元素的文本中获取的整数
连接。可使用 socket,在两个 Python 程序之间执行简单通信,还可使用 urllib 模
块连接到 Web 服务器来下载网页的内容。
最后介绍 XML,讨论如何从 XML 文档创建 ElementTree 结构,并从这些文
档提取信息。
下面是一个需要思考的有关网络的问题。
无线网络设备与有线网络设备使用相同的 Internet 版本吗?
无线设备使用的介质与有线设备不同;但在使用连接的计算机看来,两种连
接的工作方式是相同的。 Internet 协议允许传输方法(在设备之间移动数据的方式)
作为设置和管理连接的其他层之下的层存在。在第 12 章的时装店应用程序中,我
们曾使用不同对象来管理数据存储。只要完好定义了层之间的接口(一个层与另一
层的沟通方式),我们就可以将一层中的一个组件替换为另一个组件,系统的其他
部分不受此影响,将继续工作。
数据报的上限是多少?
网络的最大传输单元(Maximum Transmission Unit, MTU)确定可在一个网络
传输事务中传输的最大消息。 MTU 的大小取决于使用的传输介质。要了解不同网
络的 MTU 值,可访问 https://en.wikipedia.org/wiki/Maximum_transmission_unit。
所有数据报从一个计算机到达另一个计算机时,都经由相同的路线吗?
未必如此。 Internet 是一个互联网络的庞大集合。数据报可能必须在多个网络
之间传递,才能到达目的地。负责路由数据报的系统常根据网络各部分的忙碌程
度以及可用连接,确定最佳发送方式。 Internet 最初用于处理网络的某一部分突然
断开的情况,因此重路由是 Internet 的固有行为。它可能导致一些怪异的效果;
有时,后发送的数据报反而更早到达。如果使用套接字设置连接,网络将对程序
隐藏这些效果。
所有数据报都能到达目的地吗?
并非如此。 UDP 数据包未必能到达目的地。 TCP 数据包是会话的一部分,一
定能到达目的地。
XML 和 HTML 之间有什么区别?
XML 和 HTML 都是标记语言,故它们的名称中都包含 ML 字样。 XML 和
HTML 的内部看起来是相似的,都使用相同格式来描述元素和特性。 XML 是一个
标准,用于描述如何生成任意类型的文档。我可设计一个 XML 文档来呈现足球
得分、奶酪类型以及其他想要操纵的内容,并将这些发送给另一台计算机。 HTML
是一门标记语言,专门用于告诉 Web 浏览器如何显示网页。 HTML 包含相应的元
素,可描述文本格式、图像位置以及背景颜色等。可将 HTML 看成专用于网页的

XML 文档。
HTML 和 HTTP 之间有什么不同?
HTML (Hypertext Markup Language,超文本标记语言)告诉浏览器在屏幕上显
示什么内容。 HTTP (Hyper Text Transfer Protocol,超文本传输协议)指出如何将页
面数据(一个 HTML 文档)从服务器移到浏览器。下一章将进一步介绍 HTTP。

购买地址:

http://product.dangdang.com/25306460.html

请使用浏览器的分享功能分享到微信等