Python编程快速上手2

978-7-115-59350-4
作者: 阿尔•斯维加特(Al Sweigart)
译者: 荣耀张嘉豪
编辑: 吴晋瑜
分类: Python

图书目录:

详情

这是一本通过81个趣味小项目带你快速上手Python编程的书。如果你厌倦了循规蹈矩的教程,不妨尝试一下本书作者提倡的“做中学”方法,相信你会发现小项目程序对学习编程大有裨益。 这些项目涉及游戏、动画、数学、模拟、科学等类型,力求以最短小精悍的代码展现最丰富的创造力,以期带给读者趣味性和启发性。在了解程序的工作原理之后,你可以尝试重新创建程序,并按照书中“探索程序”部分给出的建议或自己的想法对程序加以修改。 值得一提的是,书中的大部分项目是用少于256行的代码实现的。无论是古老的数独游戏、元素周期表,还是科技感十足的诱饵标题生成器、DNA可视化,所有小项目都被设计成了独立的 Python 源文件,便于读者分享。 本书适合所有想通过 Python 学习编程的读者使用,尤其适合有 Python 基础、需要快速实现编程的读者。

图书摘要

版权信息

书名:Python编程快速上手2

ISBN:978-7-115-59350-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    [美] 阿尔•斯维加特(Al Sweigart)

译    荣 耀  张嘉豪

责任编辑 吴晋瑜

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59350”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。


Copyright © 2021 by Al Sweigart. Title of English-language original: The Big Book of Small Python Projects: 81 Easy Practice Programs, ISBN 9781718501249, published by No Starch Press Inc. 245 8th Street, San Francisco, California United States 94103. The Simplified Chinese-edition Copyright ©2022 by Posts and Telecom Press Co., Ltd under license by No Starch Press Inc. All rights reserved.

本书简体中文字版由美国No Starch出版社授权人民邮电出版社有限公司出版。未经出版者书面许可,不得复制或抄袭本书任何部分的内容。

版权所有,侵权必究。


本书旨在以“最短小精悍的代码+最丰富的创造力”的方式向读者展示81个简单、有趣的实践项目。如果你已经掌握了基本的Python语法,并且准备开始编写程序,那么阅读本书会让你觉得既有趣又很受启发。

本书给出的81个Python项目,可以助你快速上手Python编程完成数字艺术、游戏、动画、计数程序等方面的任务。一旦了解了代码是如何工作的,你就可以动手重新编写程序,并通过添加自定义的内容来不断实践。需要说明的是,书中这些项目涉及的程序大多是用少于256行的代码实现的,如蜗牛赛跑、诱饵标题生成器、DNA可视化,而且每个项目都被设计成独立的Python源文件,可供读者轻松地在网上分享。

本书适合所有想通过Python学习编程的读者使用,尤其适合有Python基础、需要快速实现编程的读者。


阿尔•斯维加特(Al Sweigart)是软件开发人员、知名作者和Python软件基金会的研究员。他曾在美国加利福尼亚州奥克兰电子游戏博物馆、艺术和数字娱乐博物馆担任教育主管。他撰写了多本编程图书,如畅销书《Python编程快速上手——让繁琐工作自动化》《Python游戏编程快速上手》等。


Sarah Kuchinsky女士是一名企业培训师和顾问。她用Python开发各种应用,包括卫生系统建模、游戏开发以及任务自动化。Sarah是North Bay Python会议的联合创始人、PyCon开发者大会的主题演讲的负责人以及PyLadies Silicon Valley的主要组织者。她拥有管理科学与工程和数学双学位。


Python是一门独特的编程语言,对于初学者和它的爱好者来说,它多少带有些玩乐的色彩——学习门槛低,容易上手,几十行代码就能实现了不起的效果。但是,当用于专业软件开发和数据分析、机器学习建模时,Python又立刻展现出作为专业编程语言严肃的一面——语法简洁富有表达力,开发效率高,运行性能好。Python具有较好的跨平台性,其生态中不乏丰富的开源工具。

不少写给初学者的编程指导书都是以枯燥乏味的小程序片段讲述编程的原理和概念,往往难以激发初学者学习编程的兴趣(兴趣是最好的老师)。这本书跟作者写的其他几本畅销书类似,均为项目导向式风格。每个小项目自成一章,先交代项目背景,接着给出程序的执行效果,然后讲解其工作原理,中间穿插一些语言语法或模块用法的解释,最后展示完整的项目代码,并提供一些思考和练习题。显然,这并不是一本系统讲解Python语言特性的入门书,不过如果你已经有一些语言基础,但在编写程序时不知从何下手,这本书就是很好的启发式读物了。

编程是一种创造性的活动,可以锻炼人的逻辑思维能力,而Python能让初学者和爱好者更容易发挥自己的创造性。无论对于有志于从事软件开发的学生,还是对于其他非职业程序员但又需要进行编程的人员(比如从事数据分析、AI模型训练的专业人员),Python都是当前进入编程世界的最佳起点。纵观编程语言发展史,Python可以算是一门“古老”的编程语言了,对于熟悉它的程序员来说,Python在大数据和人工智能时代的大放异彩让人始料未及。不过凡事有因有果。Python没有想把自己发展成为无所不能的语言,对新语言特性的加入保持克制,始终保持语言核心特性简洁,能通过库完成的全都交给库(这些库通常使用高性能C或C++编写)。在更大的场景看,Python恰如其分地发挥了“黏合剂”的作用。

阿尔•斯维加特(Al Sweigart)曾是一位软件工程师,现在全职从事Python编程布道,他聪明、有才华,在写书方面很有经验,且深谙畅销书的写作“套路”。本书中的代码写得很漂亮,充分展现了Python语言简洁、强大的特点,也初步展示了对一些数据结构和算法简单、精巧的使用。他崇尚开源(也乐于接受捐赠),开发了多个Python开源模块,并将自己的全部著作慷慨分享在个人官网上供读者免费阅读,帮助了很多Python初学者和爱好者。

本书由我和张嘉豪翻译,嘉豪做事认真踏实,富有责任心和进取心。感谢洪伊晓晨、余志昊以及晏金陈在翻译后期奉献的辅助工作。感谢浣石公司的朱艳女士在翻译过程中提供的协助。你们的奉献得以让本书以更佳的面貌呈现在读者面前。

请开始学习Python编程吧,体验编程的乐趣,自由展示你的才华和创意。祝编程之旅愉快!

荣耀 博士

于南京大行宫


如果只是跟随print('Hello, world!')这样的教程学习,你会觉得编程异常简单。你可能看过一些面向初学者的优秀图书或者相关的在线课程,也做过一些练习,而且已对大部分技术术语烂熟于心。然而,你很可能会发现,一旦离开“安乐窝”去编写自己的程序,就会寸步难行。面对空白的编辑器窗口,你可能会茫然、发呆,对如何动手编写Python程序一筹莫展。

问题的关键在于,遵循“教程非常适合学习”的主旨,与“学习从头开始编写原创程序”是两码事。通常,对于此阶段的建议是学习开源软件的源代码,或者创建你自己的项目。但有些开源项目并未提供良好的文档,也不见得特别适合新手学习。虽然开源项目会激励你创建自己的项目,但你不能从中得到系统的指导。

本书为你提供如何应用编程概念的实践示例,其中包含80多个游戏、模拟和艺术等方面的程序。重要的是,它们并非代码片段,而是完整的、可运行的Python程序。你可以复制并运行这些代码,以理解其工作方式,也可以尝试自己进行更改。作为练习,你还可以按照自己的意愿重新编写这些代码。一段时间后,你会逐渐获得自己的编程灵感,更重要的是,你将知道如何着手创建程序。

编程已被证明是一项强大的技能,它“创造”了价值数十亿美元的科技公司和惊人的技术进步。我们创建自己的软件时很容易好高骛远,“贪多嚼不烂”的后果只能是程序烂尾,而开发者也会倍感沮丧。其实,你无须成为计算机天才也能编写有趣且富有创意的程序。

本书中的Python程序遵循以下几个设计原则,有助于编程新手理解源代码。

小型:本书中大多数项目的程序不超过256行代码,这样做是为了让读者更容易理解。选择256这个行数限制没什么特别的含义,不过是因为256是2的8次方,而2的幂通常被认为是程序员的幸运数字。

基于文本:文字比图形简单。源代码和程序输出都是文本,这样便于你搞清楚代码中的print('Thanks for playing!')和屏幕上输出的Thanks for playing!之间的关系。

免安装:每个程序都保存为单独的Python源文件,其扩展名为.py,如tictactoe.py,你不需要额外运行安装程序。

丰富:本书共有81个程序,包括棋盘类、卡牌类、艺术类、模拟类、谜题类、迷宫类和诙谐类程序等。

简单:这些程序的编写方式易于初学者理解。每当不得不在使用复杂的高性能算法编写代码和编写简单、直接的代码之间做出选择时,我总是选择后者。

基于文本的程序可能看起来很老套,但采用这种编程风格可以避开下载图形、安装附加库以及管理项目文件夹等带来的干扰和陷阱,只需关注代码本身。

本书是为两类读者写的。第一类是已经学习了Python和基础编程知识但仍然不知道如何自己编写程序的人。他们可能会觉得自己不适合编程。他们也许能够完成教程中的练习,但仍然难以想象一个完整的程序是什么样子的。通过先“照抄”然后重新创建本书中的游戏,他们就能明白自己所学的编程概念是如何构成各种真实程序的。

第二类是虽然刚接触编程但兴趣浓厚并勇于探索的人。他们通常希望能立即着手编写游戏、模拟和数字运算类的程序。这类读者会在实践过程中快速成长,或者他们已经会用其他语言编程,只是不熟悉Python而已。虽然本书不能替代完整的Python入门课程,但涵盖了对Python基础知识的简要介绍,以及如何在程序运行时使用调试器检查程序的内部运作机制。

有经验的程序员也可能喜欢本书中介绍的程序,不过请别忘了,本书是为初学者写的。

本书的大部分内容专注于特色程序,同时提供了包括通用编程和Python知识在内的额外学习资源。本书包括如下内容。

项目:共有81个项目。每个项目独立介绍,包括项目名称、描述、程序运行输出示例以及程序源代码。某些项目还提供了一些对代码进行实验性修改以定制程序的建议。

附录A:标签索引,列出按项目标签分类的所有项目。

附录B:字符映射表,列出程序可以输出的符号(例如心形、线条、箭头和方块)的字符代码。

本书不像传统教程那样教授Python或编程概念,而是提供一种“做中学”的方法,鼓励你亲自动手输入程序,运行程序(像玩游戏一样),并在调试器中了解其内部工作原理。

本书的重点不在于详细解释编程语言的语法,而是展示执行实际可靠的程序示例,无论是纸牌游戏、动画,还是数学谜题的探索,均是如此。因此,我建议遵循以下步骤来学习。

1.下载程序并运行,查看程序的效果。

2.从一个空白文件开始,自己手动输入(不要复制和粘贴!)本书中的游戏代码。

3.再次运行程序,然后返回并修改你可能引入的任何拼写错误或弥补缺陷。

4.在调试器下运行程序,以便仔细地逐行运行代码,从而理解其作用。

5.找到标有!的注释,查看你可以修改的代码,然后在下次运行程序时观察自己的修改对程序有何影响。

6.尝试自己从头开始创建程序。不必完全复制程序代码,你可以在程序中融入自己的想法。

复制本书中的代码时,不必输入注释(#符号后面的文本),因为这些是给程序员看的,Python会忽略这些注释。不过,请尽量保持你的程序代码与本书中的程序代码行号相同,以便更容易进行对比。

本书中的每个程序都有一组描述标签,例如“棋盘类”“模拟类”“艺术类”“双人游戏类”等。对这些标签的解释以及标签和项目之间的交叉索引参见附录A。不过,项目是按原书英文字母顺序列出的。

Python既是编程语言的名称,也是运行Python代码的解释器软件的名称。Python软件可以免费下载和使用。你可以通过终端或命令提示符窗口检查是否已经安装了Python。在Windows上,打开命令提示符窗口,然后运行py --version。如果看到如下输出,则说明Python已安装:

C:\Users\Al>py --version
Python 3.9.1

在macOS和Linux上,打开终端程序,然后运行python3 --version。如果看到如下输出,则说明Python已安装:

$ python3 --version
Python 3.9.1

本书使用Python 3。Python 2和Python 3不完全兼容,本书中的程序至少需要Python 3.1.1(2009年发布)才能运行。

在使用Python软件运行程序之前,你需要在文本编辑器或集成开发环境(IDE)应用程序中输入Python代码。如果你是初学者,建议使用Mu Editor(简称Mu)作为IDE,它简单易用,也没有那么多“让人困扰”的高级选项。

请下载适合你的操作系统的安装程序,然后双击安装文件运行它。如果你使用的是macOS,运行安装程序会打开一个窗口,必须在其中将Mu图标拖到Applications文件夹图标上才能继续安装。如果你使用的是Ubuntu,则需要将Mu作为Python包安装。在这种情况下,打开一个新的终端窗口并运行pip3 install mu-editor进行安装,然后使用mu-editor命令运行它。单击下载页面的Python包部分的Instructions按钮,可以获取翔实的说明信息。

安装完成后,可以按照如下步骤运行Mu。

在Windows 7或更高版本上,单击屏幕左下角的开始图标,在搜索框中输入mu,并在输出的结果中选择Mu。

在macOS上,打开Finder窗口,单击应用程序,然后单击mu-editor。

在Ubuntu上,按Ctrl-Alt-T打开终端窗口,然后运行python3 -m mu。

Mu首次运行时,会出现一个选择模式窗口,其中包含以下选项:Adafruit CircuitPython、BBC micro:bit、Pygame Zero和Python 3。在本书中,我们选择Python 3,当然,也可以随时通过单击编辑器窗口顶部的模式按钮更改模式。

现在我们可以在Mu的主窗口中输入代码,然后通过顶部的按钮保存、打开和运行程序文件。

我们可以任选编辑器编写Python代码。集成开发和学习环境(IDLE)软件与Python一起安装,如果由于某种原因无法安装或运行Mu,它可以作为备用编辑器。IDLE的用法如下。

在Windows 7或更高版本上,单击屏幕左下角的开始图标,在搜索框中输入idle,然后选择IDLE (Python GUI)。

在macOS上,打开Finder窗口,单击应用程序→Python 3.9→IDLE。

在Ubuntu上,选择Applications→Accessories→Terminal,然后输入idle3。也可以单击屏幕顶部的应用程序,选择Programming,然后单击IDLE 3。

在树莓派上,单击左上角的树莓派菜单按钮,然后单击Programming和Python 3 (IDLE)。我们还可以从Programming菜单下选择Thonny Python IDE。

我们还可以使用其他几种免费编辑器输入和运行Python代码。

Thonny,一个面向初学者的Python IDE。

PyCharm社区版,这是专业开发人员使用的Python IDE。

本书中的大多数程序只需要使用Python标准库,它是随Python自动安装的。然而某些程序需要使用第三方模块,例如pyperclip、bext、playsound以及pyttsx3。这些都可以通过安装bigbookpython模块一次性安装。

对于Mu Editor,我们必须安装1.1.0-alpha版本或更高版本。截至2020年,我们可以在Code with Mu官方网站下载页面顶部的“Try the Alpha of the Next Version of Mu”部分找到此版本。安装完成后,单击窗口左下角的齿轮图标,可以调出Mu Administration窗口。选择Third Party Packages选项卡,在文本框中输入bigbookpython,然后单击OK按钮,即可安装本书程序中用到的所有第三方模块。

对于Visual Studio Code或IDLE编辑器,打开编辑器并通过交互式Shell运行以下Python代码:

>>> import os, sys
>>> os.system(sys.executable + ' -m pip install --user bigbookpython')
0

如果一切正常,第二条指令执行完成后,会输出一个0。如果你看到一条错误消息或其他数字,请尝试运行以下代码,其中没有--user:

>>> import os, sys
>>> os.system(sys.executable + ' -m pip install bigbookpython')
0

无论使用哪种编辑器,我们都可以尝试运行import pyperclip或 import bext,以检查安装是否有效。如果这些导入代码的运行没有产生错误消息,则说明这些模块安装正确,你将能够运行本书中使用这些模块的程序。

编程是一种技能,这种技能可以通过编程活动来提高。请勿仅阅读本书中的代码或仅将其简单地复制、粘贴到你的计算机上,你应该花些时间自己将代码输入编辑器——在编辑器中打开一个新文件并输入代码。为了能更好地理解这些程序,请尝试在调试器下运行它们。

输入源代码并运行成功后,请尝试对代码进行更改。标有!的注释给你提供了更改建议,每个项目还给出了较大改动的建议。

接下来,请尝试从头开始创建程序(不要查看本书中的源代码)。你的代码不必与书中的程序代码完全相同,你可以发明自己的版本!

一旦完全理解了本书中的程序,你可以着手创建自己的程序。大多数电子游戏和应用程序都很复杂,需要由程序员、艺术家和设计师组成的团队联合开发。不过,许多生活中的棋盘、纸牌和纸笔游戏通常很简单,你不妨尝试编写相应的程序。

本书用到bext模块的程序,其文本输出会以彩色显示。然而,从Mu、IDLE或其他编辑器中运行它们时,这些颜色不会显示出来。这些程序应该通过终端(也称为命令行)窗口运行。在Windows上,可以通过“开始”菜单打开命令提示符窗口。在macOS上,可以通过Spotlight运行终端。在Ubuntu上,可以通过Ubuntu Dash或按Ctrl-Alt-T快捷键运行终端。

如果终端窗口出现,则应该使用cd(更改目录)命令将当前目录更改为包含.py文件的文件夹(“目录”是“文件夹”的另一种说法)。例如,如果使用的是Windows,并将Python程序保存在C:\Users\Al文件夹内,则执行以下命令:

C:\>cd C:\Users\Al

C:\Users\Al>

要运行Python程序,应在Windows命令提示符窗口中运行python yourProgram.py,在macOS或Linux终端窗口中则应运行python3 yourProgram.py。请将yourProgram.py替换为真实的Python程序名称,示例如下:

C:\Users\Al>python guess.py
Guess the Number, by Al Sweigart al@inventwithpython.com

I am thinking of a number between 1 and 100.
You have 10 guesses left. Take a guess.
--snip--

你可以通过按Ctrl-C键(而不是关闭终端窗口)来终止从终端运行的程序。

理想情况下,你可以使用一台配备全键盘的笔记本电脑或台式计算机编写代码,因为从某种程度上讲,使用手机甚至平板电脑默认的键盘输入代码挺麻烦的。尽管没有适用于Android或iOS的成熟Python解释器,但有些网站提供了可以在Web浏览器中使用的在线Python交互式Shell。

这些网站支持本书中的大多数项目,但是不支持使用第三方模块(例如bext、pyperclip、pyttsx3以及playsound)的程序,也不支持需要使用open()函数读写文件的程序。如果程序代码中有这些内容,则这个程序无法使用在线Python解释器运行。不过,本书中的大多数程序可以正常在线运行。

除非请私人导师或程序员朋友来回答你的编程问题,否则你只能靠自己找到问题的答案。幸运的是,你的问题大多是有人问过的。“自己找到答案”是程序员要学习的一项重要技能。

如果你发现自己经常需要到互联网上查找编程问题的答案,请不要为此沮丧。你可能会觉得到互联网上找答案而不是自己记住关于编程知识的一切属于“作弊”行为,但其实只要你在不断学习,就不是“作弊”。因为即使是专业的软件开发人员,也会经常在互联网上搜索答案。

当程序尝试执行无效指令时,它会显示一条称为回溯的错误消息。回溯会告诉你发生了哪种错误以及错误发生在哪一行代码。下面是一个程序示例,它在计算每个人应该得到多少块比萨时出错:

Traceback (most recent call last):
  File "pizza.py", line 5, in <module>
    print('Each person gets', (slices / people), ' slices of pizza.')
ZeroDivisionError: division by zero

对于这个回溯提示的错误,你也许没有意识到问题在于people变量被设置为0导致表达式slices/people出现除零错误。错误消息通常很短,甚至不是完整的句子,其用意在于提醒而非完整解释。如果你是第一次遇到错误消息,可将其复制并粘贴到搜索引擎中进行搜索,通常会返回有关错误的含义及错误出现可能的原因的详细说明。

如果直接搜索无法找到问题的解决方案,你可以将问题发布到在线论坛或向某人发送电子邮件,以寻求帮助。为了使这个过程尽可能高效,请具体、清晰地描述问题,这意味着提供完整的源代码和详细的错误消息,解释你已经尝试过的做法,并确切说明你所使用的操作系统和Python版本。最终发布的答案不仅可以解决你的问题,还有助于将来遇到相同问题的程序员找到你的帖子。

打字打得飞快并不是成为一名程序员必备的技能,但这无疑是大有裨益的。有些人不会盲打,打起字来就像小鸡啄米。打字快可以让编程变得不那么麻烦。在学习使用本书中的程序时,你肯定希望自己的眼睛看着代码而不是盯着键盘。

你可以在某些网站上学习如何打字,比如TypingClub。好的打字程序会在计算机屏幕上显示键盘和一双手,让你在练习过程中避免养成低头看键盘的坏习惯。与其他技能一样,打字需要练习,你大可借编写代码来提升自己的打字技能。

善用键盘快捷键,可以免于将鼠标指针移动到菜单上再执行操作。快捷键通常写成“Ctrl-C”的形式,意味着按下键盘任一侧的Ctrl键的同时按下C键,而不是先按一次Ctrl键,再按一次C键。

使用鼠标打开应用程序顶部(在Windows和Linux中)或屏幕顶部(在macOS中)的菜单栏,你可以找到常用的快捷方式,例如Ctrl-S(保存)和Ctrl-C(复制)。磨刀不误砍柴工,花时间学习使用这些快捷键是值得的。

其他快捷键就没有那么重要了。例如,Windows和Linux上的Alt-Tab,macOS上的command-TAB,允许将焦点切换到另一个应用程序的窗口中。你可以按住Alt或command键并重复按TAB选择要切换成的特定窗口。

剪贴板是操作系统中的一项功能,可以临时存储用于粘贴的数据。这些数据可以是文本、图像、文件或其他类型的信息,这里只描述如何处理文本数据。复制文本会将当前选定文本的副本放置到剪贴板上。粘贴文本会将剪贴板上的文本输入文本光标当前所在的位置,就像你自己即刻输入的那样。复制和粘贴文本可让你免于重新输入计算机上已有的文本,无论文本是一行还是数百页。

要想复制和粘贴文本,首先要选择(或高亮显示)要复制的文本。你可以通过按住鼠标主(右)键(设置为“右撇子”鼠标的即左键)并在文本上拖动来完成文本选择。不过,按住Shift键并使用键盘快捷键移动光标通常更快、更精确。许多应用程序允许双击选定一个词。通常还可以三击选择整行或整段文本。

下一步是按Ctrl-C(在Windows上)或command-C(在macOS上)将所选文本复制到剪贴板。剪贴板只能保存一份复制的文本,复制文本操作会替换掉之前剪贴板上的任何内容。

最后,将光标定位到你希望文本出现的位置,然后按Ctrl-V(在Windows上)或command-V(在macOS上)以粘贴文本。你可以根据需要粘贴多次。复制的文本会一直保留在剪贴板上,直到复制新文本将其替换掉。

谷歌公司的搜索人类学家Dan Russell曾在其发表的一篇文章中谈到,他研究人们的计算机使用习惯时发现,约90%的人不知道可以按Ctrl-F(在Windows和Linux上)或command-F(在macOS上)在应用程序中搜索单词。这是一个非常有用的功能,不仅存在于代码编辑器中,还存在于文字处理器、Web浏览器、电子表格应用程序以及几乎所有能够显示文本的程序中。你可以按Ctrl-F调出查找文本框,输入希望在程序中查找的单词。通常,按F3键会重复该搜索并高亮显示下一个出现的该单词。与手动滚动页面查找单词相比,该功能可以为我们节省大量时间。

编辑器还具有查找和替换功能,该功能通常对应Ctrl-H或command-H快捷键,可用于定位一段文本并将其替换为另一段文本。如果希望重命名变量或函数,这个功能很有用。不过,我们要小心使用查找和替换功能,因为可能会错误替换与查找条件匹配的别的文本。

调试器是一种工具,它可以逐行运行程序,让我们能够检查程序变量的当前状态。它是跟踪程序缺陷的宝贵工具。这里解释Mu Editor调试器的功能。不用担心,基本每款调试器都提供了相同的功能,即使它们的用户界面看上去不一样。

在调试器中启动程序要使用IDE中的Debug而不是Run菜单项。调试器将被启动并暂停在程序的第一行。调试器通常都有以下按钮:Continue、Step In、Step Over、Step Out 和 Stop。

单击Continue按钮会使程序正常运行,直到终止或遇到断点(稍后会介绍断点)。如果你已完成调试并希望程序正常继续运行,可以单击Continue按钮。

单击Step In按钮会使调试器运行下一行代码,然后再次暂停。如果下一行代码是函数调用代码,调试器将“步入”该函数并跳转到该函数的第一行代码。

单击Step Over按钮会使调试器运行下一行代码,类似于Step In按钮。但是,如果下一行代码是函数调用代码,单击Step Over按钮将“跳过”函数中的代码。函数的代码全速运行,一旦函数调用返回,调试器就会暂停。Step Over按钮比Step In按钮更常用。

单击Step Out按钮会使调试器全速运行代码,直到从当前函数返回。如果你已经使用Step In按钮进入了一个函数调用,现在只想继续执行指令直到退出,单击Step Out按钮即可。

如果你希望完全停止调试且不想继续运行程序的其余部分,可单击Stop按钮。Stop按钮可以用于立即终止程序。

可以在特定行上设置断点,让程序以正常速度运行,直到到达断点所在行,此时,调试器会暂停,让我们检查变量并继续逐步运行各行代码。在大多数IDE中,可以通过双击窗口左侧的行号设置断点。

当前存储在程序变量中的值显示在调试器的调试窗口中的某处。然而,调试程序的一种常用方法是输出调试,即添加print()调用以显示变量的值,然后重新运行程序。尽管这种调试方法简单、方便,但其通常比使用调试器低效。使用输出调试方法,我们必须添加print()调用,重新运行程序,然后删除print()调用。然而,重新运行程序后,你通常会发现需要添加更多的print()调用以便查看其他变量的值。这意味着需要重新运行程序,而这次运行可能会表明需要添加另一轮的print()调用,以此类推。此外,忘记自己添加的某些print()调用并不罕见,这需要额外的删除print()调用的操作。对于简单的程序缺陷,输出调试很方便,但从长远来看,使用真正的调试器可以节省你的时间。

编程是一项有趣的、创造性的开发技能。无论你已经掌握Python语法的基础知识,还是想一头扎入真正的Python程序,本书中的项目都能够给你新的启发,让你明白用几页代码能实现些什么。

学习这些程序的最佳方法绝非仅仅阅读代码或将其复制、粘贴到计算机上。花些时间将本书中的代码手动输入编辑器,培养编写代码的肌肉记忆。这么做会减慢速度,因此你可以在输入时思考每一行代码,而不仅仅是用眼睛浏览。使用搜索引擎查找你不明白的任何指令,或在交互式Shell中对其进行实验。

最后,从头开始创建程序,然后进行修改以实现你自己想要的功能。这些练习会为你应用编程概念创建可运行的实际程序打下坚实的基础。最重要的是,希望你乐在其中!


本书由异步社区出品,社区(https://www.epubit.com)为你提供相关资源和后续服务。

本书为读者提供源代码。读者可在异步社区本书页面中单击,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

您还可以扫码右侧二维码, 关注【异步社区】微信公众号,回复“e59350”直接获取,同时可以获得异步社区15天VIP会员卡,近千本电子书免费畅读。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎读者将发现的问题反馈给我们,帮助我们提升图书的质量。

如果读者发现错误,请登录异步社区,搜索到本书页面,输入勘误信息,单击“提交”按钮即可。本书的作者和编辑会对读者提交的勘误进行审核,确认并接受后,将赠予读者异步社区的100积分(积分可用于在异步社区兑换优惠券、样书或奖品)。

扫描下方二维码,读者将会在异步社区微信服务号中看到本书信息及相关的服务提示。

我们的联系邮箱是contact@epubit.com.cn。

如果读者对本书有任何疑问或建议,请发送邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果读者有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区投稿(直接访问www.epubit.com/ contribute即可)。

如果读者所在学校、培训机构或企业想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果读者在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请将怀疑有侵权行为的链接通过邮件发给我们。这一举动是对作者权益的保护,也是我们持续为广大读者提供有价值的内容的动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近40年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、人工智能、测试、前端、网络技术等。

异步社区

微信服务号


在Pico Fermi Bagels这个逻辑推理游戏中,你要根据线索猜出一个三位数。游戏会根据你的猜测给出以下提示之一:如果你猜对一位数字但数字位置不对,则会提示“Pico”;如果你同时猜对了一位数字及其位置,则会提示“Fermi”;如果你猜测的数字及其位置都不对,则会提示“Bagels”。你有10次猜数字机会。

运行bagels.py,输出如下所示:

Bagels, a deductive logic game.
By Al Sweigart al@inventwithpython.com

I am thinking of a 3-digit number. Try to guess what it is.
Here are some clues:
When I say:    That means:
  Pico         One digit is correct but in the wrong position.
  Fermi        One digit is correct and in the right position.
  Bagels       No digit is correct.
I have thought up a number.
 You have 10 guesses to get it.
Guess #1:
> 123
Pico
Guess #2:
> 456
Bagels
Guess #3:
> 178
Pico Pico
--snip--
Guess #7:
> 791
Fermi Fermi
Guess #8:
> 701
You got it!
Do you want to play again? (yes or no)
> no
Thanks for playing!

切记,这个程序使用的不是整数值,而是包含数字的字符串值。例如,'426'与426是不同的值。之所以这么做,是因为我们需要与秘密数字进行字符串比较,而不是进行数学运算。记住,0可以作为前导数字,在这种情况下,字符串'026'与'26'不同,但整数026与26相同。

 1. """
 2. Pico Fermi Bagels猜数字游戏,作者:Al Sweigart al@inventwithpython.com
 3. 一个逻辑推理游戏,你必须根据线索猜数字
 4. 本游戏的一个版本在《Python游戏编程快速上手》中有相应介绍
 5. 标签:简短,游戏,谜题
 6. """
 7. 
 8. import random
 9. 
10. NUM_DIGITS = 3  # (!) 请试着将3设置为1或10
11. MAX_GUESSES = 10  # (!) 请试着将10设置为1或100
12. 
13. 
14. def main():
15.     print('''Bagels, a deductive logic game.
16. By Al Sweigart al@inventwithpython.com
17. 
18. I am thinking of a {}-digit number with no repeated digits.
19. Try to guess what it is. Here are some clues:
20. When I say:    That means:
21.   Pico         One digit is correct but in the wrong position.
22.   Fermi        One digit is correct and in the right position.
23.   Bagels       No digit is correct.
24. 
25. For example, if the secret number was 248 and your guess was 843, the
26. clues would be Fermi Pico.'''.format(NUM_DIGITS))
27. 
28.     while True:  # 主循环
29.         # secretNum存储了玩家所要猜测的秘密数字
30.         secretNum = getSecretNum()
31.         print('I have thought up a number.')
32.         print(' You have {} guesses to get it.'.format(MAX_GUESSES))
33. 
34.         numGuesses = 1
35.         while numGuesses <= MAX_GUESSES:
36.             guess = ''
37.             # 保持循环,直到玩家输入正确的猜测数字
38.             while len(guess) != NUM_DIGITS or not guess.isdecimal():
39.                 print('Guess #{}: '.format(numGuesses))
40.                 guess = input('> ')
41. 
42.             clues = getClues(guess, secretNum)
43.             print(clues)
44.             numGuesses += 1
45. 
46.             if guess == secretNum:
47.                 break  # 玩家猜对了数字,结束当前循环
48.             if numGuesses > MAX_GUESSES:
49.                 print('You ran out of guesses.')
50.                 print('The answer was {}.'.format(secretNum))
51. 
52.         # 询问玩家是否想再玩一次
53.         print('Do you want to play again? (yes or no)')
54.         if not input('> ').lower().startswith('y'):
55.             break
56.     print('Thanks for playing!')
57. 
58. 
59. def getSecretNum():
60.     """返回唯一一个长度为NUM_DIGITS且由随机数字组成的字符串"""
61.     numbers = list('0123456789')  # 创建数字0~9的列表
62.     random.shuffle(numbers)  # 将它们随机排列
63. 
64.     # 获取秘密数字列表中的前NUM_DIGITS位数字
65.     secretNum = ''
66.     for i in range(NUM_DIGITS):
67.         secretNum += str(numbers[i])
68.     return secretNum
69. 
70. 
71. def getClues(guess, secretNum):
72.     """返回一个由Pico、Fermi、Bagels组成的字符串,用于猜测一个三位数"""
73.     if guess == secretNum:
74.         return 'You got it!'
75. 
76.     clues = []
77. 
78.     for i in range(len(guess)):
79.         if guess[i] == secretNum[i]:
80.             # 正确的数字位于正确的位置
81.             clues.append('Fermi')
82.         elif guess[i] in secretNum:
83.             # 正确的数字不在正确的位置
84.             clues.append('Pico')
85.     if len(clues) == 0:
86.         return 'Bagels'  # 没有正确的数字
87.     else:
88.         # 将clues列表按字母顺序排序,使其不会泄露数字的信息
89.         clues.sort()
90.         # 返回一个由clues列表中所有元素组成的字符串
91.         return ' '.join(clues)
92. 
93. 
94. # 程序运行入口(如果不是作为模块导入的话)
95. if __name__ == '__main__':
96.     main()

输入源代码并运行几次后,请试着对其进行更改。标有!的注释给你提供了更改建议。你也可以自己尝试执行以下操作。

通过更改NUM_DIGITS修改秘密数字的位数。

通过更改MAX_GUESSES修改玩家的最大猜测次数。

尝试创建秘密数字中包含字母和数字的程序版本。

请尝试找出以下问题的答案。可尝试对代码进行一些修改,再次运行程序,并查看修改后的效果。

1.如果更改NUM_DIGITS常量,则会发生什么?

2.如果更改MAX_GUESSES常量,则会发生什么?

3.如果将NUM_DIGITS设置为大于10的数字会发生什么?

4.如果将第30行的secretNum = getSecretNum()替换为secretNum = '123',会发生什么?

5.如果删除或注释掉第34行的numGuesses = 1,会得到什么错误消息?

6.如果删除或注释掉第62行的random.shuffle(numbers),会发生什么?

7.如果删除或注释掉第73行的if guess == secretNum:和第74行的return'You got it!',会发生什么?

8.如果注释掉第44行的numGuesses += 1,会发生什么?

微信扫码关注【异步社区】微信公众号,回复“e59350”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

“生日悖论”又称为“生日问题”,是指即使在很少的一群人中两人生日相同的概率也是惊人的。在一个70人的组中,两人生日相同的概率高达99.9%。即使在一个只有23人的小组中,这个概率也高达50%。以下程序用于进行多个概率实验,以确定不同规模小组中生日相同的概率值。这类实验称为蒙特卡罗实验。在这类实验中,我们需要进行多次随机试验,以了解可能的结果。

运行birthdayparadox.py,输出如下所示:

Birthday Paradox, by Al Sweigart al@inventwithpython.com
--snip--
How many birthdays shall I generate? (Max 100)
> 23

Here are 23 birthdays:
Oct 9, Sep 1, May 28, Jul 29, Feb 17, Jan 8, Aug 18, Feb 19, Dec 1, Jan 22,
May 16, Sep 25, Oct 6, May 6, May 26, Oct 11, Dec 19, Jun 28, Jul 29, Dec 6,
Nov 26, Aug 18, Mar 18

In this simulation, multiple people have a birthday on Jul 29

Generating 23 random birthdays 100,000 times...
Press Enter to begin...
Let's run another 100,000 simulations.
0 simulations run...
10000 simulations run...
--snip--
90000 simulations run...
100000 simulations run.
Out of 100,000 simulations of 23 people, there was a
matching birthday in that group 50955 times. This means
that 23 people have a 50.95 % chance of
having a matching birthday in their group.
That's probably more than you would think!

运行100000次模拟可能需要耗费一些时间,这就是后文的完整程序中第91行和第92行报告另外10000次模拟已经完成的原因。该反馈可以让用户确信程序没有“僵死”。注意,某些整数(例如第91行的10_000以及第89行和第99行的100_000)带有下划线。这些下划线没有特殊含义,但Python允许这么做,这样程序员可以让整数更易于阅读。换句话说,将100_000(而不是100000)读成“十万”更容易一些。

  1. """生日悖论,作者:Al Sweigart al@inventwithpython.com
  2. 探索生日悖论的惊人概率
  3. 标签:简短,数学,模拟"""
  4. 
  5. import datetime, random
  6. 
  7. 
  8. def getBirthdays(numberOfBirthdays):
  9.     """返回一个随机生日日期对象的数字列表"""
 10.     birthdays = []
 11.     for i in range(numberOfBirthdays):
 12.         # 年份对于模拟并不重要,假设所有生日在同一年即可
 13.         startOfYear = datetime.date(2001, 1, 1)
 14. 
 15.         # 随机获取一年中的一天
 16.         randomNumberOfDays = datetime.timedelta(random.randint(0, 364))
 17.         birthday = startOfYear + randomNumberOfDays
 18.         birthdays.append(birthday)
 19.     return birthdays
 20. 
 21. 
 22. def getMatch(birthdays):
 23.     """返回在生日列表中多次出现的日期对象"""
 24.     if len(birthdays) == len(set(birthdays)):
 25.         return None  # 若所有生日都不同,则返回None
 26. 
 27.     # 将这个生日与其他生日进行比较
 28.     for a, birthdayA in enumerate(birthdays):
 29.         for b, birthdayB in enumerate(birthdays[a + 1 :]):
 30.             if birthdayA == birthdayB:
 31.                 return birthdayA  # 返回相同的生日
 32. 
 33. 
 34. # 显示介绍信息
 35. print('''Birthday Paradox, by Al Sweigart al@inventwithpython.com
 36. 
 37. The birthday paradox shows us that in a group of N people, the odds
 38. that two of them have matching birthdays is surprisingly large.
 39. This program does a Monte Carlo simulation (that is, repeated random
 40. simulations) to explore this concept.
 41. 
 42. (It's not actually a paradox, it's just a surprising result.)
 43. ''')
 44. 
 45. # 创建一个按照月份排序的元组
 46. MONTHS = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
 47.           'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
 48. 
 49. while True:  # 要求玩家输入有效的总数
 50.     print('How many birthdays shall I generate? (Max 100)')
 51.     response = input('> ')
 52.     if response.isdecimal() and (0 < int(response) <= 100):
 53.         numBDays = int(response)
 54.         break  # 玩家输入了有效的总数,结束循环
 55. print()
 56. 
 57. # 显示生成的生日
 58. print('Here are', numBDays, 'birthdays:')
 59. birthdays = getBirthdays(numBDays)
 60. for i, birthday in enumerate(birthdays):
 61.     if i != 0:
 62.         # 每个生日之间用逗号隔开
 63.         print(', ', end='')
 64.     monthName = MONTHS[birthday.month - 1]
 65.     dateText = '{} {}'.format(monthName, birthday.day)
 66.     print(dateText, end='')
 67. print()
 68. print()
 69. 
 70. # 确定是否存在两个相同的生日
 71. match = getMatch(birthdays)
 72. 
 73. # 显示结果
 74. print('In this simulation, ', end='')
 75. if match != None:
 76.     monthName = MONTHS[match.month - 1]
 77.     dateText = '{} {}'.format(monthName, match.day)
 78.     print('multiple people have a birthday on', dateText)
 79. else:
 80.     print('there are no matching birthdays.')
 81. print()
 82. 
 83. # 运行100000次模拟
 84. print('Generating', numBDays, 'random birthdays 100000 times...')
 85. input('Press Enter to begin...')
 86. 
 87. print('Let\'s run another 100000 simulations.')
 88. simMatch = 0  #模拟中有多少相同的生日
 89. for i in range(100_000):
 90.     # 每10000次模拟后输出当前进度
 91.     if i % 10_000 == 0:
 92.         print(i, 'simulations run...')
 93.     birthdays = getBirthdays(numBDays)
 94.     if getMatch(birthdays) != None:
 95.         simMatch = simMatch + 1
 96. print('100000 simulations run.')
 97. 
 98. # 显示模拟结果
 99. probability = round(simMatch / 100_000 * 100, 2)
100. print('Out of 100,000 simulations of', numBDays, 'people, there was a')
101. print('matching birthday in that group', simMatch, 'times. This means')
102. print('that', numBDays, 'people have a', probability, '% chance of')
103. print('having a matching birthday in their group.')
104. print('That\'s probably more than you would think!')

尝试找出以下问题的答案。尝试对代码进行一些修改并重新运行程序以查看修改代码后的效果。

1.程序是如何表示生日的?(提示:请查看第13行代码。)

2.如何取消程序最多生成100个生日的限制?

3.如果删除或注释掉第53行的numBDays = int(response)会得到什么错误消息?

4.如何让程序显示完整的月份名称,例如显示January而不是Jan

5.如何让“× simulations run...”每执行1000次模拟(而不是每执行10000次模拟)出现1次?

微信扫码关注【异步社区】微信公众号,回复“e59350”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

本项目中的程序用多行字符串表示位图,即“每个像素”只有两种可能颜色的二维图像,以确定如何显示来自用户的消息。在位图中,空格字符代表一个空格,其他字符都被用户消息中的字符所替换。输出的位图有点像地图的样子,你也可以将其修改为自己喜欢的任何图案。因为使用的是简单的二元“空格或消息”字符系统,所以本项目很适合初学者。你可以尝试不同的消息,看看效果如何!

运行bitmapmessage.py,输出如下所示:

Bitmap Message, by Al Sweigart al@inventwithpython.com
Enter the message to display with the bitmap.
> Hello!

Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!He
  lo!Hello!Hello    l  !He lo  e      llo!Hello!Hello!Hello!Hello!He
 llo!Hello!Hello!Hello  He lo H  l !Hello!Hello!Hello!Hello!Hello H
el      lo!Hello!Hello!He        lo!Hello!Hello!Hello!Hello!Hel
         o!Hello!Hello           lo  e lo!H ll !Hello!Hello!H l
          !Hello!He             llo!Hel   Hello!Hello!Hell ! e
          Hello!He             ello!Hello!Hello!Hello!Hell H
 l        H llo! ell           ello!Hello!Hell !Hello el  o
             lo!H  l           ello!Hello!Hell   ell!He   o
               !Hello           llo!Hello!Hel    el  He   o
               !Hello!H          lo!Hello!Hell    l !H ll o
                 ello!Hel           Hello!He         H ll o Hell
                 ello!Hell           ello!H  l       Hell  !H l o!
                 ello!Hell           ello!H l o           o!H l   H
                   lo!Hel            ello! el             o!Hel   H
                   lo!He              llo! e            llo!Hell
                  llo!H               llo!              llo!Hello
                  llo!                ll                 lo!Hell   e
                  llo                                         l    e
                  ll    l                       H
Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!He

图案顶部和底部两行各有的68个字符作为标尺,用于帮助我们正确对齐。不过,即使你在输入图案时打错了字符,该程序仍然可以正确运行。

调用第40行的bitmap.splitlines()方法会返回一个字符串列表,每个字符串都是多行bitmap字符串中的一行。使用多行字符串易于将位图修改为你喜欢的任何图案。程序会填充图案中的所有非空格字符。这也是使用星号、句点或其他字符运行效果都相同的原因。

第48行代码message[i % len(message)]会使message中的文本重复出现。当i0增加到大于len(message)的数值时,表达式i % len(message)再次为0。这会导致message[i % len(message)]随着i的增加而重复message中的字符。

 1. """位图消息,作者:Al Sweigart al@inventwithpython.com
 2. 根据提供的位图图像显示文本消息
 3. 标签:小,初学者,艺术"""
 4. 
 5. import sys
 6. 
 7. # (!) 尝试将这个多行字符串更改为你喜欢的任何图案
 8. 
 9. # 此字符串的顶部和底部各有68个字符
10. bitmap = """
11. ....................................................................
12.    **************   *  *** **  *      ******************************
13.   ********************* ** ** *  * ****************************** *
14.  **      *****************       ******************************
15.           *************          **  * **** ** ************** *
16.            *********            *******   **************** * *
17.             ********           ***************************  *
18.    *        * **** ***         *************** ******  ** *
19.                ****  *         ***************   *** ***  *
20.                  ******         *************    **   **  *
21.                  ********        *************    *  ** ***
22.                    ********         ********          * *** ****
23.                    *********         ******  *        **** ** * **
24.                    *********         ****** * *           *** *   *
25.                      ******          ***** **             *****   *
26.                      *****            **** *            ********
27.                     *****             ****              *********
28.                     ****              **                 *******   *
29.                     ***                                       *    *
30.                     **     *                    *
31. ...................................................................."""
32. 
33. print('Bitmap Message, by Al Sweigart al@inventwithpython.com')
34. print('Enter the message to display with the bitmap.')
35. message = input('> ')
36. if message == '':
37.     sys.exit()
38. 
39. # 循环遍历bitmap字符串中的每一行
40. for line in bitmap.splitlines():
41.     # 循环遍历一行中的每一个字符
42.     for i, bit in enumerate(line):
43.         if bit == ' ':
44.             # 输出空格,以表示位图中的空格
45.             print(' ', end='')
46.         else:
47.             # 输出message中的一个字符
48.             print(message[i % len(message)], end='')
49.     print()  # 输出一行空行

输入源代码并运行几次后,请尝试对其进行更改。你可以通过修改bitmap变量中的字符串来创建全新的图案。

请尝试找出以下问题的答案。你需要尝试对代码进行一些修改,再次运行程序,查看修改后的效果。

1.如果玩家输入空字符串,会发生什么?

2.bitmap字符串中的非空格字符是什么,重要吗?

3.第42行的i变量代表什么?

4.如果删除或注释掉第49行的print(),会出现什么错误?

微信扫码关注【异步社区】微信公众号,回复“e59350”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

相关图书

深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
动手学自然语言处理
动手学自然语言处理
Web应用安全
Web应用安全
Python高性能编程(第2版)
Python高性能编程(第2版)
图像处理与计算机视觉实践——基于OpenCV和Python
图像处理与计算机视觉实践——基于OpenCV和Python
Python数据科学实战
Python数据科学实战

相关文章

相关课程