面向青少年的-Python-教程-全-

面向青少年的 Python 教程(全)

原文:Python for teenagers

协议:CC BY-NC-SA 4.0

一、计算机编程和 Python 简介

计算机编程——通常被酷孩子称为“编码”——是创建应用或软件的艺术。这些程序允许我们做任何事情,从解决简单的数学问题和观看我们最喜欢的 YouTube 视频(我对跳伞牛头犬百看不厌),到在我们最喜欢的视频游戏中摧毁成群猖獗的外星人,甚至将现实生活中的宇宙飞船发射到外太空。

我称计算机编程为“艺术”,因为它就是。任何时候你创造东西,你都在沉迷于一种艺术形式。当然,计算机代码,也就是我们输入到 shell 中来创建程序的单词(稍后会有更多内容!),对于街上的普通人来说可能看起来并不漂亮——你的代码很可能永远不会看到艺术展览的内部——但是当你的程序的一部分做了你创建它的目的时……几乎没有什么比这更神奇的了。

也许那些跳伞斗牛犬。

计算机程序可以有多种形状和大小。除了在你的桌面系统上运行的应用或在你最喜欢的视频游戏控制台上玩的游戏,程序还以移动应用的形式出现在手机上。你甚至可以找到操作冰箱、你妈妈的小货车,甚至像烤面包机这样简单的东西的软件。

还有机器人。机器人大军。

但稍后会详细介绍。

现在,我们知道计算机程序是一组代码,用一种编程语言创建,告诉设备执行一组指令。

编程语言概述

如上所述,计算机程序是使用编程语言编写的。就像你、我和世界上其他人每天说的真正的语言一样,计算机语言有各种各样的形式和大小。虽然对于受过训练的人来说,它们中的大多数是有意义的,但如果一个代码新手试图在日常对话中使用它们,听起来就像一个疯子在胡言乱语。该对话可能看起来像这样:

Normal Person: Hello, how are you?
Programmer (You): Print I am fine! Input, how are you?

幸运的是,对所有参与者来说,计算机在编程语言方面都很流利(这部分要感谢我们的朋友编译器——但稍后会有更多的介绍!)并能轻松理解您键入的最复杂的句子。

出于本书的目的,我们将坚持使用最通用、最容易学习的语言之一, Python 。虽然这个名字听起来很可怕,但请记住,它可能更糟:它可能被称为眼镜蛇。事实上,这种语言根本不是以一种爬行动物命名的,而是来自英国的一部古老的电视喜剧《??:巨蟒和飞行马戏团》。

这是你的第一个任务:去问问你父母关于那个节目的事。几小时后见!

哦,你回来了。太好了。他们说的有意义吗?可能不会。不过没关系;你不需要理解英国喜剧的复杂性来学习如何使用这本书编程。你所需要的只是学习的欲望,一台电脑,和你面前的书页。

Python 概述

Python 是一种高级的、动态的、解释的、面向对象的编程语言。虽然所有这些听起来有点吓人,但不要害怕!到本书结束时,你将能够用比上面更令人畏惧的句子来打动你的朋友!这句话的真正意思是,Python 不是一种基本的机器语言,因此,它需要一个“解释器”来将其“编译”成机器语言,以便计算机可以理解您试图告诉它的内容。

这个解释器获取你的代码,并将其转换——或编译—成一系列计算机能明白的 1 和 0。所有这些都是在后台发生的,所以如果你还没有完全理解,不要担心。

Python 是一种相对较新的编程语言,创建于 20 世纪 80 年代末——那时你的父亲留着很大的滑稽小胡子,你的母亲听着名字像 Wham 这样的乐队。

创造这种语言的人是一位名叫吉多·范·罗森的计算机天才,他被赋予了一个奇特而荒谬的头衔,终身仁慈的独裁者。像技术一样,编程语言也在发展,Python 也不例外。多年来,它经历了几个版本,目前被称为 Python 3。

Python 和其他编程语言有什么不同?

Python 与其他编程语言在许多不同但重要的方面有所不同。首先,Python 通常比同类语言(如 Java 和 C++)更容易学习和使用。用 Python 创建的程序也花费更少的时间,因为它需要更少的代码(一般来说)。这部分是由于 Python 的数据类型——我们将在下一章详细介绍这个术语。

Python 也是极其通用的。虽然 Python 可能不是首选,但它可以用于几乎每个领域的应用,包括游戏、桌面软件、移动应用,甚至虚拟现实。它也是网络编程的必备工具,是计算机安全工具箱中的必备工具。

Python 的优势

Python 是当今世界上最常用的编程语言,也是发展最快的语言。有充分的理由。下面是 Python 可以让程序员受益的几个方面:

  • 提高生产力:根据一些报告,Python 可以提高程序员的生产力——他们在给定时间内可以完成多少工作——十倍之多!它真的比子弹还快!

  • 可扩展性:Python 的一个巨大优势是它有一个非常广泛的库。库是一组可以添加到程序中的现有代码。这些库涵盖了程序的常见特性,让您不必自己一遍又一遍地编写代码。例如,不需要编写一段代码来执行一个复杂的数学方程,你可以提供使用一个库来为自己省去一个大麻烦。

  • Python 易于阅读:作为一名程序员,一个棘手的问题是,有时你的代码无法工作。当这种情况发生时,你可能会发现自己在重读自己的代码——或者更糟,重读别人的代码——试图找出为什么你的程序没有正常运行。幸运的是,Python 易于阅读,大部分语言一看就明白。这使得发现问题比更复杂的语言容易得多。

  • 可移植性:Python 可以在许多平台和系统上运行,这意味着您的程序可以面向更广泛的受众。

  • 物联网(IoT):物联网可能听起来像是一个充满数字野兽的神奇世界,从某些方面来说,的确如此。物联网由智能物体组成,包括电灯开关、门把手、烤面包机、家用电器,你可以在日常生活中找到它们。这些家用电器可以通过语音命令和移动设备进行控制,使它们比原始的前辈更具交互性。我的意思是,当然,你的父母总是对着洗碗机大喊——但是它听进去了吗?现在,由于物联网和 Python 等语言,它可以做到!你仍然要把你的盘子放在里面,但是仍然!

  • Python 框架:框架就像程序的骨架——它们允许你快速地为某些类型的应用建立基础,而不需要编写你正在开发的软件类型中通常存在的通用元素。这节省了程序员的时间,并减少了手工编码时可能出现的错误。Python 得到了大量框架的支持,这使得启动一个新程序变得非常迅速!

  • Python 很有趣:Python 是一门有趣的学习语言;如上所述,不仅入门容易,Python 社区还举办了许多有趣的活动和挑战。例如,许多人以诗歌的形式编写他们的 Python 代码,每年都有大量的 Python“挑战”来帮助测试一个程序员的技能。

  • Python 是灵活的:因为 Python 有如此多的用途,被世界上如此多的公司使用,所以学习 Python 后找工作比学习其他语言更容易。此外,如果您不喜欢某个给定的领域,您可以随时使用您的 Python 技能尝试不同的途径。例如,如果你发现编写应用很无聊,你可以转到网络管理或在 IT 安全公司工作。

这些只是 Python 提供的一些好处和优势。

野生蟒蛇的例子

虽然很难说世界上有多少公司使用 Python,但是有许多有趣的业务依赖于这种语言。以下只是其中的一小部分:

  • 韦恩企业(蝙蝠侠的另一个自我的公司):嗯,我们真的不知道,但那不是很酷吗?

  • Google:搜索引擎巨头和未来的统治者 Google 从一开始就使用 Python,部分原因是开发人员可以用它快速构建程序,也因为代码易于维护。

  • 脸书和 Instagram:虽然 Python 不是这两个社交媒体平台使用的唯一语言,但它是它们最重要的语言之一。脸书使用 Python,部分原因是因为它有丰富的库。与此同时,Instagram 是 Python 的主要 web 框架之一——Django 的坚定支持者。我们将在本书的后面详细讨论 web 框架。

  • 网飞:如果你是流媒体电影的粉丝,那么你对网飞一定不陌生。该公司主要将 Python 用于其数据分析功能和安全目的——以及其他领域。

  • 电子游戏:《战地 2》和《文明 4》只是两款都依赖于 Python 的电子游戏。有趣的是,文明使用 Python 作为人工智能(AI)脚本。

  • 政府机关和机构:政府机关和机构包括美国宇航局、国家气象局和中央情报局都使用 Python——尽管如何使用它是绝密的!带着装满钱的公文包在车库等我们,我们会告诉你一切!

你的第一个 Python 程序

现在,您可能想知道 Python 代码是什么样子的。别害怕!我将向您展示一个样本片段。稍后,在我们在您的计算机上安装 Python 和 IDLE(集成开发环境)之后,您可以尝试执行或运行代码来查看它的运行情况。但是现在,我认为在深入研究这种语言之前,让您体验一下是一个好主意。

传统上,当程序员编写他们的第一行代码时,他们会创建一个名为“Hello,World”的程序,作为向世界介绍自己的一种隐喻方式。然而,作为崭露头角的超级英雄——或者恶棍(这里不做评判)——我们需要一些更闪亮的东西。

看,你的第一个 Python 程序!

print("Look up in the sky! Is it a bird? Is it a plane?")
print("Dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun")
print("No you dummy. That's just some guy flying around in his pajamas. Now get back to work!")

如果您运行这段代码,结果将是:

Look up in the sky! Is it a bird? Is it a plane?

Dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun

No you dummy. That's some guy flying around in his pajamas. Now get back to work!

让我们更仔细地检查一下代码。说明 print() 的部分被称为函数,它的工作是告诉计算机——在这个例子中是—在用户的屏幕上打印一些东西。左括号和右括号()之间的文本是我们提供给函数的参数。引号" "之间的字符称为字符串。

如果这还没有完全理解,请不要担心——我们将在下一章详细讨论这个话题。现在,只要知道这就是 Python 代码的样子。很有可能,在我告诉你之前,你能够准确地说出这个程序将做什么;这只是 Python 如此伟大的原因之一——它的可读性!

安装 Python

在本节中,我们将学习如何在各种操作系统上安装 Python。操作系统是一种让你与计算机互动的软件。你可能很熟悉那些更受欢迎的,比如微软 Windows (如果你有个人电脑的话)和 Mac OS X (如果你有苹果电脑的话)。您安装的 Python 版本将根据您的计算机使用的版本而有所不同。此外,我们还将学习如何在 Linux 和 Ubuntu 系统上安装 Python。

在 Windows 上安装 Python

首先,打开 web 浏览器,导航到 Python 官方网站及其下载页面: www.python.org/downloads/ (图 1-1 )。

img/468718_1_En_1_Fig1_HTML.jpg

图 1-1

Python。org 网站

Python 目前的版本是 3 . 6 . 5;等你读到这本书的时候,可能还会更高。无论是哪种情况,点击下载 Windows 最新版本标题下的“下载 Python”按钮。或者,您可以向下滚动并下载以前的版本(只要确保它们是版本 3。x 或更高版本,因为版本 2 之间存在不兼容问题。x 和 3。x);但是,出于本书的目的,最好使用 3.6.5 或更高版本。

将出现一个图像,询问您是否要保存该文件。点击“保存文件”(图 1-2 ),将其保存到您的桌面或易于记忆的地方。

img/468718_1_En_1_Fig2_HTML.jpg

图 1-2

Python 安装文件的保存文件对话框

导航到您的桌面(或您保存文件的位置)并双击它。它应该类似于图 1-3 中的图像。

img/468718_1_En_1_Fig3_HTML.jpg

图 1-3

Python。EXE 安装文件图标

安装程序将启动,并询问您是希望“立即安装”还是“自定义安装”为方便起见,我们将允许安装程序“立即安装”但是,在单击该按钮之前,请确保“为所有用户安装启动器”和“将 Python 3.6 添加到路径”都已选中。然后点击“立即安装”选项(图 1-4 )。

img/468718_1_En_1_Fig4_HTML.jpg

图 1-4

Python 安装设置屏幕

Windows 可能会弹出一个窗口,询问您是否允许继续安装。如果是这样,请允许程序继续运行。将出现一个新的弹出窗口,显示设置进度(图 1-5 ):

img/468718_1_En_1_Fig5_HTML.jpg

图 1-5

Python 安装进度屏幕

设置完成后,您将看到如下所示的屏幕。点击“关闭”按钮完成安装(图 1-6 )。

img/468718_1_En_1_Fig6_HTML.jpg

图 1-6

Python 安装设置成功窗口

现在,您的计算机上应该已经安装了 Python。您可以在您的“开始”菜单中找到它,标签为 Python 3.6(或您安装的任何版本)。

当您启动 Python 时,首先看到的是 shell,它是开发环境的一部分,您可以在其中编写一行代码、测试代码、运行代码和创建 Python 文件。图 1-7 显示了 Python Shell 启动后的外观示例。

img/468718_1_En_1_Fig7_HTML.jpg

图 1-7

Python 外壳

在这个 shell 窗口的顶部,您可以看到 Python 的当前版本和一些其他信息。您还会看到三个大于号或箭头(> > >)。这些被称为命令提示符,您将在这里向 Python 输入指令。

准备好开始了吗?让我们输入一些简单的代码,看看会发生什么!在提示符下输入以下内容:

print("Look up in the sky! Is it a bird? Is it a plane?")

完成后,按回车,你应该会看到如下结果(图 1-8 ):

img/468718_1_En_1_Fig8_HTML.jpg

图 1-8

用 Python Shell 编写的示例代码

如果没有,请重新检查您的代码,确保拼写正确,并记住插入括号()和引号“”。

因为我们直接在 shell 中工作,所以我们的代码会被实时执行。在这个例子中,它运行了一行代码,告诉计算机在屏幕上打印一行文本。

在现实世界中,我们想要创建实际的 Python 文件,以便我们可以保存我们的程序供以后使用,并帮助我们在每次运行我们的程序时避免重新编写数千行代码。

幸运的是,Python IDLE——或开发环境——允许我们创建 Python 文件,即以扩展名结尾的文件。py,相当容易。你所要做的就是点击文件,然后新文件(见图 1-9 、 1-10 和 1-11 )。

img/468718_1_En_1_Fig11_HTML.jpg

图 1-11

显示 Python 目录的保存对话框

img/468718_1_En_1_Fig10_HTML.jpg

图 1-10

用. py 文件编写的示例代码

img/468718_1_En_1_Fig9_HTML.jpg

图 1-9

新创建的。py 文件

将弹出一个新窗口。这是您可以编写代码并保存以备后用的地方。也就是说,让我们输入刚才使用的示例代码。然后点击文件,再保存

接下来点击文件,然后保存

输入文件名,点击保存按钮,完成文件创建。出于本书的目的,让我们保持简单,将我们的文件命名为 Example1.py

现在,你已经创建了你的第一个真实世界的 Python 程序。要运行该程序,请单击“运行”,然后选择“运行模块”。您的程序现在将在 Python shell 中执行!(图 1-12 )。

img/468718_1_En_1_Fig12_HTML.jpg

图 1-12

的结果。py 文件在 Python Shell 中运行

现在,让我们总结一下:还记得我们在本章开始时写的第一个程序吗?让我们将它输入到 Example1.py 文件中,完成后单击保存。下面是代码:

print("Look up in the sky! Is it a bird? Is it a plane?")
print("Dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun dun")
print("No you dummy. That's just some guy flying around in his pajamas. Now get back to work!")

一旦你保存了文件,点击运行并选择运行模块来查看运行中的完整代码!(图 1-13 )。

img/468718_1_En_1_Fig13_HTML.jpg

图 1-13

Python Shell 中运行的. py 文件的另一个例子

在其他操作系统上安装 Python

本书使用安装在基于 Windows 的计算机上的 Python 虽然里面的代码可以在任何一台计算机上运行,但是 Python 的实际安装会因操作系统的不同而有所不同。

要在 Mac OS X 上安装 Python,请打开 web 浏览器并导航至 www.python.org/downloads/mac-osx/ 。选择“最新 Python 3 版本”链接,按照说明和提示完成设置和安装过程。

要在 Unix/Linux 系统上安装 Python,打开浏览器,进入 www.python.org/downloads/source 。单击“最新 Python 3 版本”的链接,并按照说明完成设置和安装过程。

在这一集里!

我们在这一章中确实讲了很多,但与我们在下一章将要揭示的相比,这根本不算什么!这里有一个简短的列表——如果你愿意的话,是一个总结——列出了我们到目前为止所涉及的内容(嘿,我们现在是编程英雄了,我们也要说行话了!)

  • Python 是一种编程语言,可以让你对计算机、移动设备、视频游戏、人工智能系统、物联网(IoT)设备、基于网络的应用,甚至虚拟现实/增强现实(VR/AR)进行编程。

  • 程序或应用是一组代码,让你给计算机或设备一组指令来执行。

  • 了解 Python 的程序员可以从事编程、网络管理、IT 安全、视频游戏开发、移动应用创建、法医计算机科学等职业。

  • Python 可以跨多个平台工作,包括 Windows PCs、Mac 计算机、移动设备、Unix/Linux 驱动的计算机等等。

  • Python 可以通过一组被称为“道德黑客”工具的技能和模块来防止黑客攻击。

  • IDLE 代表集成开发环境;这是我们创建 Python 代码和文件的地方。

  • Python 创建的文件以文件扩展名结尾。py”。

  • 在撰写本文时,Python 的当前版本是 3.6.5。如果你在读这本书,一定要用这个版本或者更新的版本。

  • print()功能允许您将文本打印到用户的屏幕上。例如,print("Hello Wall!")将打印文本:Hello Wall!对着电脑屏幕。

  • 全球许多组织和公司都在使用 Python,包括脸书、谷歌、Snapchat、NASA、中情局等等!

  • Python 是世界上使用最多的——也是发展最快的——计算机编程语言。

二、把一切加起来

既然我们都穿上了隐喻的斗篷和超级英雄的装备(也就是说,我们已经安装了 Python 并学会了如何使用 IDLE),是时候测试我们的新超能力了!我们的第一个恶棍?也许是有史以来最邪恶、最卑鄙、最轻蔑的野兽之一;一个学校系统的罪犯,横行无忌,威胁要摧毁——或厌烦——它所经过的每一个学生。反派的名字?

数学。

我知道,这不是最令人兴奋的话题。至少,乍一看不是。然而,事实是,数学,更重要的是,数学函数是编程世界的面包和黄油。没有数学,我们就无法做计算机和移动设备允许我们做的任何漂亮的事情。不会有电脑游戏,不会有太空飞船,不会有未来的机器人来帮助我们打扫肮脏的房间。

没有数学,我们将真正成为一个失落的文明。

因此,本章的目的将是如何使用 Python 的一些内置的数学函数来处理数学和创建简单或复杂的数学方程。

类似于我们在第一章中学到的 print()函数,我们将要讨论的数学函数将让我们对数据执行预先构建的操作,而不必编写应用的公共元素。所以,举个例子,而不是写一大堆代码向计算机解释什么是加法,如何实际相加数字(记住,计算机只能做我们告诉它的事情;它不能独立思考——至少现在不能!),如果我们从头开始,这将需要数千行代码,我们所要做的就是键入一些简单的内容,例如:

1+1

继续——将它输入 Python shell。当你这样做时,它应该忠实地返回答案:2。

就像你在学校学到的数学一样,Python 天生就能理解基本的数学函数。如果你看到这个:8/2,你的大脑知道这个等式涉及除法。如果看到+ 符号,很明显是加法,a -表示减法。Python 也理解这些符号,并将基于它们执行数学运算。尝试在 Python shell 中键入以下内容:

2+2-1

在这个实例中,Python 将返回 3,表明它能够理解常见的数学运算符。Python 中的运算符包括:+、-和/-等等。

乘法怎么样?键入以下内容:

2x2

那里发生了什么?程序没有像我们预期的那样返回 4。相反,它返回了一个语法错误:无效语法异常。SyntaxErrors 意味着您输入到 shell 或 Python 文件中的语法(即书面文本)有问题,导致程序无法正常运行。

换句话说,Python 不懂你。

这里,解决方案很简单:在 Python 中,乘法运算符不是“x”,而是一个星号(*)。要修复我们的语法错误,我们所要做的就是用正确的乘法运算符替换错误的乘法运算符,就像这样:

2*2

现在,如果你输入,它将返回预期的响应——数字 4。

运算符优先级

邪恶的反派数学的超能力之一就是用看起来太难把握的概念来迷惑我们。不要害怕!凭借我们超级英雄的计算能力,即使是最复杂的数学谜语也难不倒我们。

不是说它不会尝试,请注意!

在 Python 中执行计算时,我们必须时刻注意一个叫做操作符优先级的东西。这只是对 Python 处理数学问题的顺序的一种想象。某些运算符的优先级比其他运算符高,这意味着它们排在第一位。可以想象,这可能会让程序员感到困惑,即使是最有经验的老手也会在输入计算时出错。

为了让您更清楚地了解运算符优先级是如何工作的,下面是 Python 中的一个运算符列表,按照优先级或等式中谁先开始排序。注意:其中一些操作符可能对您来说并不熟悉——现在不要太担心;我们将在本书中详细介绍它们。

  • **(取幂运算)

  • *、/(乘法和除法)

  • +,-(加法和减法)

  • 在,不在,是,不是,,> =,!=,==(这些被称为比较,允许您将一个值与另一个值进行比较)

  • 不是 x

  • 单位

  • 或者

  • 语句

为了简单起见,让我们使用基本运算符:*、/、+ 和-(乘法、除法、加法和减法)。在您的 shell 中键入以下内容:

10+10 * 20

在这个等式中,我们在问 10 加上 10 乘以 20 的值是多少。通常,我们认为答案应该是 400,因为第一个值 10 加 10 应该等于 20。然后,我们将答案(20)乘以 20,得到 400。然而,当我们在 shell 中输入代码时,我们得到了一个令人惊讶的结果,如图 2-1 所示。

img/468718_1_En_2_Fig1_HTML.jpg

图 2-1。

运算符优先级示例

你的第一个想法可能是:Python 数学不好吗?怎么得出的答案:210?出现这种情况是因为运算符优先级。请记住,在我们的运算符优先级列表中,乘法优先于加法。因此,Python 首先对乘法求值,然后进行数学运算。在这个例子中,Python 是这样看待我们的等式的:20 * 10 + 10。

我知道你在想什么:我头疼。

乍一看,这似乎令人困惑,但幸运的是,有一个简单的解决方案。我们可以通过使用括号来强制 Python 使用一个求值顺序——执行计算的顺序。这有两个效果:首先,它确保 Python 执行我们想要的计算,并且不会混淆我们的优先级。第二,它让其他程序员看一眼就知道你真正想要的是什么。

让我们试一试。在您的 shell 中键入以下内容:

(10+10)  * 20

如图 2-2 所示,现在我们得到了想要的结果。通过将(10+10)放在括号内,我们告诉 Python——以及其他编码人员——我们打算首先执行等式的这一部分(见图 2-2 )。

img/468718_1_En_2_Fig2_HTML.jpg

图 2-2。

使用括号强制排序的运算符优先级示例

让事情变得稍微复杂一点,我们还可以做一些被称为嵌套的事情。这意味着您将圆括号放在其他圆括号的内,以进一步指示应该执行什么顺序计算。在这种情况下,首先计算最里面的括号,然后是最外面的,然后是等式的其余部分。考虑一下这个:

((10+5) * 10) / 2

如果您将该等式输入 Python,它将按照以下方式执行求值顺序:

  • 十加五等于十五

  • 15 * 10 等于 150

  • 150 / 2 等于 75

然而,如果我们不使用括号,Python 会这样理解:

10 + 5 * 10 / 2

或者

  • 10 / 2 等于 5

  • 5 * 5 等于 25

  • 25 + 10 等于 35

这也是因为在考虑运算符优先级时,Python 在加法和减法之前执行乘法和除法

所以,为了避免任何混淆,除了简单的数学运算之外,在执行任何运算时都要使用括号。

数据类型:了解你的敌人

超级恶棍有各种形状和大小。你有你的邪恶科学家,一心想用死光和转基因大猩猩毁灭世界;有邪恶的绿色的,荡漾着肌肉和充满愤怒,因为...嗯,没有真正的好理由。还有一些人一直在笑,尽管没有人讲过一个笑话。

有成千上万种类型的恶棍,作为一个初出茅庐的超级英雄,你可以打赌很难让他们都井然有序。Mindblower 先生是一个超级聪明的人,还是一个被人误解的无法统一行动的恶棍?神秘的斯蒂芬·金刚(Stephen King Kong)——半大猩猩半恐怖的作家——他到底是什么?他是怎么用大猩猩的大指关节写出这么多书的?

这足以让你失去理智。

还是那个吹牛老爹又在工作了?

幸运的是,有一种方法可以让所有这些恶棍组织起来。这叫做原型。

在 Python 中,我们也有类似的问题。有各种各样的数据在流动。首先我们有数字和文字。更糟糕的是,我们有不同类型的数字。有常规数字,有带小数的数字,还有代表时间或金钱的数字。甚至有一些数字的行为方式与单词的行为方式相同。

幸运的是,在 Python 中有一种叫做数据类型的东西。这些是定义或分类你输入到程序中的数据类型的方法。虽然这似乎应该是常识——有时确实如此——但事实是,Python 只知道您告诉它知道的东西。所有的计算机语言都是如此。事实上,所有的计算机语言都有数据类型,就像 Python 一样,所以数据类型的概念是你在学习其他语言时可以随身携带的。

我们将在本书中讨论几种数据类型的形式,但在本章中,我们将集中讨论一个特定的集合:数字。

一般来说,Python 将数字识别为数字,但是,正如您所想象的,并不是所有的数字都是平等的。简单来说,现在,你看到的任何一个整数或者没有小数点的数字都叫做整数。整数包括 0、2、5、10、100、1000、1032 等数字。

尝试以下代码:

print(122)

您的结果应该是这样的(参见图 2-3 ):

img/468718_1_En_2_Fig3_HTML.jpg

图 2-3。

打印整数

正如我们前面看到的,整数不仅仅是打印到用户的屏幕上——我们还可以进行计算。让我们试试下面的方法:

print(5/2)

这段代码运行时会发生一些有趣的事情,如图 2-4 所示:

img/468718_1_En_2_Fig4_HTML.jpg

图 2-4。

在 print()函数中执行数学运算

返回的数字不符合整数的标准,尽管我们对两个整数执行了数学运算。每当一个数字有小数时,它就不再被认为是整数数据类型;相反,它是一个浮点数。

正如我们可以在整数上执行等式一样,我们也可以在浮点数上执行等式。我们在图 2-5 中展示了一个例子:

img/468718_1_En_2_Fig5_HTML.jpg

图 2-5。

浮点数据类型

当一个 float 被添加到另一个 float 时,结果是另一个 float。即使这个数字看起来应该是一个整数,也是如此。比如我问 2.5 + 2.5 的结果,你大概会回答:5。让我们看看 Python 对此有什么看法:

从图 2-6 中可以看到,Python 做了一些我们可能没有预料到的事情:它返回了 5.0——一个浮点数。

img/468718_1_En_2_Fig6_HTML.jpg

图 2-6。

在两个浮点数上执行数学运算

虽然这是一个合适的结果,但我们可能会发现自己处于需要更改数字的数据类型的情况。例如,我们可能有一个程序,其中我们不想显示小数点或想四舍五入我们的数字。在这种情况下,一种选择是转换我们的数字。

然而,在我们了解这一点之前,让我们再尝试一件事。当我们对一个整数和一个浮点数执行数学运算时会发生什么?尝试以下操作(参见图 2-7 ):

img/468718_1_En_2_Fig7_HTML.jpg

图 2-7。

从整数中减去浮点数的结果

print(5 - 2.5)

你的结果应该是:

任何时候你对一个整数和一个浮点数执行数学运算,结果都是一个浮点数。

转换数字数据类型

我们要学习的第一件事是如何将一个整数转换成一个浮点数。在前面的例子中,我们使用了一个简单的方法将整数转换成浮点数:除法。我们可以实现相同效果的另一种方法是使用 Python 的内置函数之一,称为float()

使用float()非常简单——你所要做的就是把你想要转换的整数放在括号()内。让我们试一试!

float(12)

如果您在 Python Shell 中键入该内容,将会得到以下结果:

img/468718_1_En_2_Fig8_HTML.jpg

图 2-8。

将整数转换为浮点数

如图 2-8 所示,你的结果应该是 12.0 (而不是仅仅常规的没有小数点的 12)。

要做相反的事情——将浮点数转换成整数——我们使用 Python 的另一个超级方便的内置函数。请看,int()

功能int()的工作原理与float()相同。只需在括号中输入你想要转换的数字,Python 就会完成剩下的工作。尝试一下:

int(12.0)

这将返回:

img/468718_1_En_2_Fig9_HTML.jpg

图 2-9。

将浮点数转换为整数

如图 2-9 所示,我们取了一个浮点数——12.0——并通过去掉小数点将其转换为整数 12。

如果我们有一个不以. 0 结尾的浮点数会怎么样?让我们通过一个简单的测试来了解一下。在您的 Python Shell 中键入以下内容:

int(12.6)

当你按下回车键,你会得到结果:12。为什么不是 13?当您将浮点数转换为整数时,Python 会删除小数点后的所有内容并忽略它。如果你想向上取整(或向下取整),你需要使用一个不同的函数,我们将在本书的后面介绍。

有许多数据类型可以转换成其他数据类型,我们将在本书中介绍其余的数据类型。然而现在,给自己一点掌声吧——你的武器库中又增加了两个新的超级能力:int()float()函数!

什么是变量?

到目前为止,我们已经学习了一些基本的数学运算符和函数,可以用来将数据类型从一种转换为另一种。然而,为了让我们拥有真正的力量,我们需要了解一种被称为变量的秘密武器。

有几种简单的方法可以让变量变得更容易理解。一种方法是把它们想象成一个盒子,你可以在里面存放东西。在我们的例子中,我们存储的是数据。这些数据可以是数字,可以是文本,可以是货币价值,可以是你的狗的名字,可以是一段文字,也可以是你秘密巢穴的安全密码。

变量在 Python 和其他编程语言中有许多功能。变量的最大用途之一是存储信息,这样我们就不必一遍又一遍地不断输入信息。例如,您可能有一长串经常使用的数字。不用每次需要的时候都输入这个长长的列表,你可以把它存储在一个变量中,然后调用这个变量。

要使用一个变量,你只需要给它一个名字,然后定义它的值。例如:

a = 8675309

这段代码创建变量名“a”,然后给它赋值,在本例中是 8675309。

当然,存储数据是一回事;使用这些数据是另一回事。让我们继续创建一个简单的程序,它将为两个变量提供一些数据,然后将其打印到用户的屏幕上。还记得如何从我们的第一个程序示例中创建新的 Python 文件吗?在 Python Shell 中,点击文件,然后新建文件。将弹出一个新窗口。在新窗口中输入以下代码:

a = 500
b = 250
print(a)
print(b)

接下来,点击文件,然后保存。将文件命名为 VariableTest.py 。要查看运行中的代码,请单击运行,然后单击运行模块。

代码将在 Python Shell 中运行,如图 2-10 所示:

img/468718_1_En_2_Fig10_HTML.jpg

图 2-10。

打印两个变量的值

如你所见,我们给变量 a 赋值 500,然后给变量 b 赋值 250。然后,使用 print 函数,我们打印出两个变量的值。现在来点真正的乐趣吧!

公平地说,打印出变量的值相当无聊。然而,打印并不是我们可以对变量做的唯一事情。让我们修改 VariableTest.py 的代码。将以下代码添加到文件中,使其看起来像这样:

a = 500
b = 250
print(a)
print(b)

print(a+b)

保存文件,然后再次运行以查看结果,结果应与图 2-11 相匹配:

img/468718_1_En_2_Fig11_HTML.jpg

图 2-11。

显示了添加和打印两个变量的结果

这里,我们创建了两个变量,并给它们赋值,就像之前一样。我们还把它们打印了出来。然而,这次我们也对它们进行了一些数学运算,并打印出了结果。行中的代码:print(a +b)告诉 Python 打印 print()函数的括号()内的任何内容——在本例中,我们说打印等式(a) + (b ),即 750。

请注意,这个不会改变变量“a”或“b”中的数据值——它只是使用它们执行数学运算。要更改变量内部的数据,我们有几个不同的选项。让我们创建一个新文件,并将其命名为 VariableChange.py。

a=500
b=250

a=a+b

print(a)

运行代码查看结果(如图 2-12 所示):

img/468718_1_En_2_Fig12_HTML.jpg

图 2-12

将两个变量的结果赋给一个变量

这里发生了什么?首先,我们命名并定义了变量“a”和“b”的值。然后,我们将两个变量的值相加,并重新分配变量“a”的值,以匹配该方程的结果。然后,我们打印出变量“a”来显示新值,即 750。

当我们输入 a=时,我们告诉 Python 将“a”的值改为等号(=)后面的值。接下来,Python 将“a”和“b”相加,并将该值赋回“a”。等号(=)被称为赋值运算符

如果我们不想改变变量“a”的值,我们也可以创建一个全新的变量。让我们修改 VariableChange.py 中的代码,使其符合以下内容:

a=500
b=250

c=a+b

print(c)

这一次,我们没有改变“a”的值,而是简单地创建了一个新变量“c”,并赋予它“a”+“b”的值,然后打印出“c”的内容。

超级英雄发电机 3000

现在我们已经有了一些代码经验,让我们用它来构建我们将在本书结束时创建的程序的基础。该计划将是一个超级英雄生成器,让用户创建英雄(或恶棍)完成统计数据,随机名称,随机生成的权力和统计数据。

下面的一些代码将向我们的程序添加文本,我们将在第三章中详细介绍。现在,我们将只使用这些文本作为标签,所以你理解代码应该没有问题。

每个英雄都有一定的身体和精神属性。如果你以前玩过角色扮演游戏——或者 RPGs 那么你应该对这个概念很熟悉。如果没有,不用担心!看看你周围的人,观察他们。举例来说,你的体育教练可能有肌肉,而且身材很好。这意味着他比你的科学老师更有力量和耐力。

另一方面,你的科学老师可能比你的体育教练更聪明、更有智慧,这意味着他有更多的智力智慧。让我们从这些属性开始,作为我们的前四个统计数据。我们可以在以后添加更多。

为了确定每个值,我们需要指定一个从低到高的范围。我们现在可以使用 0-20 的范围,0 代表低,20 代表高。所以,如果我们讨论的是力量,那么 0 代表非常弱,20 代表大力士。因此,平均值为 10。

同样,对于智力,我们可以说 0 是门把手(因此有“像门把手一样笨”的说法),20 是阿尔伯特·爱因斯坦。任何在 10 分范围内的人都被认为智力一般。

现在,我们可以允许玩家设置他们自己的属性分数,但是,我们知道每个人都会把他们设置为 20,成为最强壮,最聪明的人。虽然这确实完美地定义了你和我,但其他凡人达不到这些高标准。

相反,我们想要做的是随机地给它们的属性赋值。Python 能够使用一个名为random()的函数非常容易地创建随机数。

*使用random()和其他函数有点不同。要使用它,我们首先要把它import成 Python。我们用一行简单的代码做到了这一点:

import random

random()函数像其他函数一样工作,因为您可以将参数赋给它的括号。创建名为 RandomGenerator.py 的新 Python 文件,并输入以下代码:

import random

strength = random.randint(1,20)

print(strength)

在这段代码中,我们首先导入 random()模块,然后创建一个名为“strength”的变量。关于变量有一点需要注意。在编程界有一种叫做命名约定的东西。这意味着在给事物命名时,你应该遵循某些“规则”。对于一个变量,你总是想给它们起一个名字,让你或未来的程序员知道变量中保存的是什么类型的数据。例如,将一个变量命名为“a ”,并不能给我们提供多少信息。将其命名为“强度”告诉我们里面的数据到底是干什么用的。

如果您的变量名中有多个单词,请始终将它们作为一个单词,只需将第二个单词的第一个字母大写。例如,如果我们的变量是“英雄强度”,我们会将其命名为 Hero Strength。如果是“英雄力量统计”,我们会用 heroStrengthStats。

第二条经验法则是尽可能保持简洁。记住,变量是用来节省输入代码的时间的,所以长名字会使目的落空。

回到代码…

在创建了我们的变量“强度”之后,我们想给它赋值。代码的下一部分调用 random()模块,并使用一个名为randint的属性。Randint 是 random()的一部分,它告诉 Python 不仅要创建一个随机数,还要创建一个随机整数。我们放在括号中的值是随机数的范围。记住,我们希望我们的统计范围在 1 到 20 之间,因此,我们输入的值是(1,20)。

尝试多次运行 RandomGenerator.py 中的代码。每次都应该得到一个随机数:

现在我们已经有了我们的随机数生成器,并且了解了如何使用它,让我们添加一些更多的统计数据:

import random

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

接下来,我们需要将这些值打印到屏幕上进行测试。为此,我们将使用一些文本作为标签,然后在标签后打印每个变量的值。在变量后添加以下代码:

print("Your character's statistics are:")
print("Strength:", strength)
print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

这里我们遇到了 print()函数的不同用法。之前,我们使用 print()打印数字和变量。然而,现在我们使用一种新的数据类型,称为字符串。字符串就是文本。它可以包含任何字母、特殊字符(!、@、#、$、%、^、&、、-、+、=等。),以及任何数字。但是,要将其视为文本,它的必须*放在引号" "之间。如果不是,Python 会把它解释成别的东西。现在不要太担心这个——我们会在第三章中详细讨论。现在,让我们检查一行代码:

print("Your character's statistics are:")

这段代码实际上告诉计算机将“你的角色的统计数据是:”打印到屏幕上。

下一条指令略有不同:

print("Strength:", strength)

这个 print()函数做两件事。首先,它说打印括号之间的文本:“强度:”。然后,我们添加一个逗号(,),告诉 Python 对 print()函数有进一步的说明。接下来,我们包括我们想要打印其内容的变量的名称——在本例中,变量 strength 。请注意,变量不在引号中。如果是,它将只打印单词“strength ”,而不是名为 strength 的变量的内容。

现在,您的 RandomGenerator.py 文件应该如下所示:

import random

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

print("Your character's statistics are:")
print("Strength:", strength)
print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

让我们运行几次代码。请记住,我们的程序创建随机生成的数字,因此每次执行代码时,结果都会有所不同。图 2-13 显示了它应该看起来的样子:

img/468718_1_En_2_Fig13_HTML.jpg

图 2-13。

生成随机统计数据

恭喜您,您刚刚创建了超级英雄生成器 3000 应用的开始部分!

在这一集里!

在这激动人心的一集里,我们涉及了很多内容。你开始只是一个年轻的助手,但是你的力量正在稳步增长!很快你就会从神奇小子变成…神奇侠?我不知道——我们会想出名字的。真正重要的是,你已经像超级英雄一样迈出了编码之路的第一步。

前方有什么危险?下一章,我们将看看如何处理文本,并继续构建我们的超级英雄生成器 3000 应用。我们也将开始记录和评论我们的工作,如果你希望成为其中一个伟大的人,这是一个强制性的编程练习!

在我们继续之前,让我们先看看在这一期中我们学到了什么:

  • 数据类型:数据类型存在于所有编程语言中,有助于定义程序处理的数据种类。integer–或 int–是整数的数据类型,而 float 是浮点数或带小数的数字的数据类型。

  • 运算符优先级:在执行等式时,某些运算符优先于其他运算符。

  • 运算符:常见的运算符有+(加)、-(减)、*(乘)、和/(除)。

  • 赋值操作符:等号(=)是一个赋值操作符,允许你给一个变量赋值。

  • 运算顺序:数学运算的执行顺序称为运算顺序。我们可以通过在括号中封装部分来控制在一个等式中首先执行哪种数学运算。例如:(1+1) * 10 确保 1+1 在乘法之前执行,尽管事实上乘法的运算符优先级高于加法。

  • 转换数据类型:int()和 float()分别允许我们将浮点数转换为整数,将整数转换为浮点数。

  • 变量:变量是数据的存储单位。您也可以将它们视为指向数据位置的标签,但是将它们视为可以包含一条信息的盒子可能更容易。我们通过命名变量并用赋值操作符给它们赋值来创建变量。比如:a = 12。

  • 命名约定:命名约定是一些松散的规则,有助于简化编码——对于你和任何将来阅读你的代码的程序员。请将它们视为“最佳实践”例如,在给一个变量命名时,第一个单词总是用小写字母,后面的任何单词都用大写字母。一定要把多个单词组合成一个单词。比如:socialSecurity 好。社会保障不好,会导致语法错误。此外,尽量用简短的名称命名变量,以描述变量中的数据的用途。

  • random()和 randint(): random()是一个可以生成随机数的模块。您必须使用代码 import random 将它导入到您的程序中。要随机生成具有给定数字范围的整数,请分别键入 random.randint(1,20)或 random.randint(5,100 )(如果要随机生成 1 到 20 或 5 到 100 的数字)。如果您想生成 0 到 20 之间的数字,您必须在代码中指定,例如:random.randint(0,20)。*

三、把东西串起来

欢迎无畏的英雄回来!关于超级英雄和反派(尤其是反派),你应该知道一件事——他们往往相当担心。谢天谢地,这一章是关于增加你的能力,给你新的超能力来处理所有文本和文本相关的事情!

我们将学习处理和操作文本的基础知识,包括常见的文本函数和关于文本数据类型的细节。我们还将讨论格式化文本和将文本转换成不同的数据类型。最后,我们将讨论好的文档的重要性,以及如何对代码进行注释,从而为您和未来的程序员省去很多麻烦。

所以穿上你的亮绿色紧身衣,戴上橙色的口罩。清除你的神奇男孩(或女孩)标志上的番茄酱污渍,让你的手指变得漂亮灵活。

准备编码!

在门口留下你的评论

在我们更深入地研究编程语言之前,有必要讨论一个我们已经提到过但目前还在回避的话题。就像正确的命名惯例一样,注释或记录代码的艺术是一个好的程序员经常实践的最佳实践之一。这有点像在你离开家之前熨你的斗篷。当然,你可以跳过它,但这样你就冒着你的死对头取笑你的风险。

有几个理由来评论你的代码。首先,程序员经常不得不在比他们第一次编程时更晚的时间回顾他们的代码。这可能是几天,几周,几个月,甚至几年。回顾成千上万行代码是很费力的,尤其是当你必须确定每一部分是做什么的时候。如果您对您的部分进行了标记并提供了简短的描述,那么导航和找到问题区域或部分就变得更加容易,您可能需要在以后进行更新。

你应该练习记录你的代码的另一个原因是其他程序员可能需要在某个时间点回顾它。这些程序员可能是你的老板,你的同事,或者是未来的程序员,他们甚至在被雇佣之前就需要对你写的东西进行修改。

最后,有时候你会在另一个程序中重用一个程序的代码——我们称之为效率(当然,前提是你的公司允许你这么做!).在这些情况下,如果您已经注释/记录了您的工作,找到您正在寻找的代码片段将会快得多。

程序员留下评论有许多不同的方式——每个人都有自己的风格。一些公司可能要求你用一种非常具体的、格式化的风格来记录你的代码,而其他公司则由你来决定。

另一件事:当注释写在你的代码中时,解释器或编译器会忽略它们。这意味着它们根本不会影响您的代码——除非您使用错误的语法输入它们。

要进行注释,可以使用标签或#符号。该行剩余部分中出现在#之后的任何内容都被视为注释。下面是一个注释示例:

# This block of code randomly calculates a hero's stats.

如果运行这段代码,也不会发生任何事情,因为 Python 忽略了注释。他们不是为了计算机消费而存在的,只是为了人类和次人类(也就是程序员)。

让我们看看代码旁边的注释是什么样子的。还记得上一章的 RandomGenerator.py 文件吗?将其打开,并向其中添加以下文本:

import random

# This block of code randomly calculates a hero's status.

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

print("Your character's statistics are:")
print("Strength:", strength)
print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

正如您所看到的,这使得更容易看到那段代码的确切用途。我们可以在代码片段的末尾添加另一个注释,使其更加清晰:

import random

# This block of code randomly calculates a hero's status.

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

# End random calculation code

print("Your character's statistics are:")
print("Strength:", strength)
print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

这里的想法是指出代码中做不同事情的每一部分的结束和开始点。正如您所想象的,这种文档很容易让人忘乎所以,但是它也有它的好处。你评论的多少或者多长时间评论一次取决于你自己,但是作为一个规则,记录总比不记录好。

阻止评论

除了常规注释,还有一种注释形式叫做块注释。当您需要不止一行来解释一段代码时,可以使用这种类型的注释。如果您需要记录编写代码的日期、编写代码的人等等,也可以使用它。请看下面演示块注释的代码:

# Importing the random function
import random

# This code was written by James Payne
# To be published in Python for Teenagers by Apress Books
# This block of code randomly calculates a hero's status.

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

# End of random number generator code

#Prints out player statistics
print("Your character's statistics are:")
print("Strength:", strength)
print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

如您所见,要阻止注释,您需要做的就是在您要留下注释的每一行的开头添加一个散列符号(#)。

内嵌注释

另一种注释方式叫做内联注释。这意味着你在代码的同一行留下一个注释。它们不像其他形式的注释那样常见,但是如果您需要记录特定代码行的作用,它们会很有用。例如,在我们的 RandomGenerator.py 文件中,我们从导入 random 开始。虽然这一行代码对于查看您的代码的程序员来说应该是显而易见的,但是我们可以留下一个行内注释来解释它。

这是它看起来的样子:

import random      # Importing the random module

通常,尽量避免使用行内注释,除非你觉得需要解释一行代码的作用。

注释的其他用途

在代码中留下注释的最后一个用途是:查找错误。虽然这听起来不合常规,但实际上非常实用。有时您的代码可能会给您带来错误,您可能需要缩小代码的哪个部分是罪魁祸首。你可以只注释掉部分,而不是大规模删除 Python 的部分。请记住,当 Python 看到#符号时,它会忽略该行中跟在它后面的任何字符。

如果我们注释掉下面的代码,它的运行方式将与以前不同:

import random

strength = random.randint(1,20)
intelligence = random.randint(1,20)
endurance = random.randint(1,20)
wisdom = random.randint(1,20)

print("Your character's statistics are:")
# print("Strength:", strength)
# print("Intelligence", intelligence)
print("Endurance", endurance)
print("Wisdom", wisdom)

有了这段代码,我们就不会在屏幕上看到角色的力量或智力,因为我们注释掉了那部分代码。相反,只有耐力和智慧会显示出来。

要让程序回到正常状态,我们只需删除#符号。您可以随意在代码中添加注释,并注释掉部分代码,看看它对您的程序有什么影响。

发短信——不用手机

既然我们已经理解了注释的重要性以及如何注释来记录我们的代码,我们可以继续处理下一个数据类型, strings

字符串数据类型由您可以键入的任何字符组成,只要它包含在引号" "中。本质上,它是任何字母、数字或特殊符号。它可以是一个字母、一个句子,也可以是字母、数字和特殊符号的组合。

让我们创建一个名为 LearningText.py 的新文件。向其中添加以下文本:

# This is how you print text

print("Holy smokes, it's the Grill Master!")

如果您愿意,也可以选择使用单引号来编写代码:

# This is how you print text

print('Holy smokes, it's the Grill Master!')

然而,如果您运行第二个版本的代码,您将得到一个无效的语法错误。你能找出为什么会这样吗?让我们更仔细地检查一下代码。我们知道 print()函数将打印引号之间包含的任何内容。虽然我们的句子以单引号结束和开始,但如果你仔细看,你会看到第三个引号——在单词“it's”中。

当我们在打印函数中使用单引号时,我们必须小心,因为 Python 无法区分在缩写中使用的引号和撇号。当它看到单词 Holy 前的第一个引号时,它开始参数。然后,当它遇到单词 it's 中的撇号时,解释者会感到困惑,并将其视为结束引用。最后,它遇到第三个单引号并抛出一个错误。

有几种方法可以避免这类问题。首先,作为一个规则,总是使用双引号。第二,在你需要或者想要使用单引号的情况下,一个转义可以解决你的问题。

escape 键本质上是一个反斜杠()字符,它告诉 Python 将单引号视为常规字符。要使用它,只需将它添加到希望 Python 将其视为纯文本的字符之前。你应该这样编码:

# This is how you print text

print('Holy smokes, it\'s the Grill Master!') # Notice the use of the escape key

现在,如果您运行代码,您将得到如图 3-1 所示的结果:

img/468718_1_En_3_Fig1_HTML.jpg

图 3-1

使用 escape 键格式化打印语句

为了简单起见,现在让我们回到在代码中使用双引号。去改变吧,我会在这里等你。

完了?太好了。让我们再添加几行文本:

# This is how you print text

print("Holy smokes, it's the Grill Master!")
print("His sizzling meats are too good to resist!")
print("Quick Wonder Boy! Get some Wonder Bread and make me a sandwich!")
print("To quote a genius: 'Man Cannot Live On Bread and Water Alone!'")

该代码的目的有两个。首先,它向您展示了如何打印几行文本。其次,它展示了一个可以互换使用双引号和单引号的例子。当使用正确的语法时,当引用某人的话时,必须使用单引号。

在这种情况下,单引号不需要转义。这是因为我们用双引号开始了 print()函数。只有当我们用单引号开始函数时,我们才需要担心转义另一个单引号,该单引号并不是用来结束函数的。

使用字符串和变量

就像我们处理数字一样,字符串可以存储在变量中。该方法类似于存储一个数字,只是略有不同:

name = "Grillmaster"

print(name)

我们首先创建名为“name”的变量,然后向其中添加一些文本。请注意,与我们对数字所做的不同,我们用引号将值括起来。这意味着我们正在向变量中添加一个字符串。接下来,我们使用 print()函数将变量打印到用户屏幕上。

这就是事情变得有趣的地方。创建一个新文件,并尝试以下代码:

age = "42"
graduation = 27

print(age + graduation)

如果您试图运行这段代码,您会得到一条错误消息。为什么呢?原因很简单:当我们声明名为“age”的变量时,我们给它赋值“42”。然而,由于我们用引号将值括起来,Python 将该数据解释为 string 数据类型。与此同时,“毕业”变量被指定为数字数据类型。当我们试图对两个变量执行数学运算时,它不起作用,因为你不能对一个字符串执行数学运算。

有趣的是,你可以在字符串上使用某些数学运算符。在 Python 和其他语言中,有一种东西叫做串联。当您将一个字符串添加到另一个字符串或将它们连接在一起时,就会发生串联。我们使用加法(+)操作符——或者在字符串上使用时使用连接操作符。这是代码:

print("Wonder" + "Boy")

当您测试这段代码时,您的结果将是:

元宝

如果对两个包含字符串的变量使用+ 运算符,也会发生同样的情况:

firstName = "Wonder"
lastName = "Boy"

print(firstName + lastName)

结果呢?

元宝

一个重要的注意事项:如果你想把两个字符串加在一起,你可以考虑在中间加一个空格。这可以通过在要连接的第一个字符串的末尾添加一个空格来实现:

print("Wonder " + "Boy")

或者在要连接的第二个字符串前添加一个空格:

print("Wonder" + " Boy")

当然,没有什么可以阻止您插入包含空格的第三个字符串:

print("Wonder" + " " + "Boy")

这是可行的,因为在 Python 的眼里,即使是一个空格也被认为是一个字符串或字符。

另一个可以在字符串上使用的数学运算符是乘法()运算符——或者在处理文本时被称为字符串* 复制运算符。尝试在 Python Shell 中键入以下代码:

print("WonderBoy" * 20)

这导致如图 3-2 所示的结果:

img/468718_1_En_3_Fig2_HTML.jpg

图 3-2

字符串复制的结果示例

如果你用这段代码创建一个文件,对一个包含字符串的变量执行字符串重复,你会得到类似的结果,如图 3-3 所示:

img/468718_1_En_3_Fig3_HTML.jpg

图 3-3

对变量执行字符串复制

sidekick="WonderBoy"
print("You ruined the Grill Master's barbeque!")
print("The crowd is chanting your name!")
print(sidekick *20)

更长的字符串

如果字符串只限于一个字符或一个单词,它就不会很强大。如前所述,字符串可以由完整的句子组成,我们在变量中声明它们,就像声明一个单词一样:

joke = "Why did Spiderman get in trouble with Aunt May?"
punchline = "He was spending too much time on the web."

print(joke)
print(punchline)

多行字符串

有时您可能会发现,您希望以特定的方式打印文本,或者像打印诗歌或歌词一样组织文本。在这种情况下,您可以创建一个多行字符串。为此,您只需使用三个双引号(" ")或三个单引号(' ')。这是一个代码示例。请随意创建一个新文件,并亲自测试它。您应该会看到图 3-4 中展示的相同结果:

img/468718_1_En_3_Fig4_HTML.jpg

图 3-4

创建多行字符串打印语句

print("""My name is Grill Master
and I have an appetite
For destruction
That is well done!""")

使用三个单引号也可以获得相同的结果:

print('''My name is Grill Master
and I have an appetite
For destruction
That is well done!''')

格式化字符串

虽然使用多行字符串可以帮助您格式化文本和字符串,但您也可以使用其他更好的方法。也许你想给一个女孩或男孩留下深刻印象,邀请他们参加一个花哨的邀请或正在努力为你的新主题曲填词。不管怎样,如果没有合适的字符串格式器,你的文本将会是平淡无奇的。

没有灵感是一个英雄最不应该做的事。

之前我们讨论过转义字符 ()。我们学习了如何使用它让 Python 像对待 print()函数的结尾那样对待撇号。事实上,有几种不同的转义字符,每一种都能以特定的方式格式化文本。它们如下:

  • \允许您在多行字符串中创建新行

  • \用于格式化反斜杠

  • \n 创建换行符

  • \t 创建制表符或缩进

  • \ '或\ "用于单引号或双引号

为了更好地理解我们表中列出的转义字符的用法,让我们看一看“\n”或换行符。这个转义符允许我们在插入文本时创建一个新的行。

创建一个新的 Python 文件,并将其命名为 WonderBoyTheme.py。在该文件中输入以下代码:

print("My name is\nWonder Boy\nAnd it is a wonder\nThat I can fit in these tights!")

乍一看,这段代码非常混乱。然而,当我们运行程序时,我们可以确切地看到\n是如何工作的(图 3-5 )。

img/468718_1_En_3_Fig5_HTML.jpg

图 3-5

在单个 print()函数中格式化字符串

通常,当我们查看这行代码时,我们会期望 print()函数中的所有内容都在一行中打印出来。但是,\n 转义会在 Python 每次遇到它时强制换行,而是格式化我们的文本,使其出现在单独的行上。

\t转义以类似的方式工作,除了它不创建新行;相反,它在文本中进行缩进或制表符。让我们在 WonderBoyTheme.py 文件中添加更多的文本:

print("My name is\nWonder Boy\nAnd it is a wonder\nThat I can fit in these tights!")
print("There trunks are \ttight")
print("tight \ttight \ttight \tso very tight!")

如果运行这段代码,它将返回如图 3-6 所示的结果:

img/468718_1_En_3_Fig6_HTML.jpg

图 3-6

使用转义符的更多示例

蜘蛛侠只希望他有一个主题宋立科!

请注意在示例图中,单词“紧,紧,紧,非常紧”是如何用制表符缩进的?这都要感谢\t

最后,我们再来重温一下\"\'转义字符。如前所述,有时你可能想使用引用作为你打印到屏幕上的实际文本的一部分,这导致了一个问题,因为 Python 不能区分你想要什么引用被用于,除非你告诉它

为了让 Python 知道您想在语法意义上而不是编程意义上使用引号,您只需对它们进行转义。让我们在 WonderBoyTheme.py 文件中添加更多的文本。确保你的和我的一致:

print("My name is\nWonder Boy\nAnd it is a wonder\nThat I can fit in these tights!")
print("There trunks are \ttight")
print("tight \ttight \ttight \tso very tight!")
print("\n")
print("And when the people see me they all shout and agree:")
print("\"Boy, those tights are too tight for he!\"")

运行这个程序,看看结果,如图 3-7 所示:

img/468718_1_En_3_Fig7_HTML.jpg

图 3-7

使用 escape \t 创建制表符缩进

请特别注意代码的这一部分:

print("\"Boy, those tights are too tight for he!\"")

第一个双引号(")告诉 Python 它后面的任何内容都要打印到屏幕上。然后,Python 遇到了反斜杠(),并知道将它后面的字符视为常规文本。然后,Python 遇到另一个反斜杠(),并再次将它后面的字符视为简单文本。最后,它遇到了最后一个双引号,因为它前面没有转义字符或反斜杠,所以它知道您打算用它来表示您希望打印的文本的结尾。

注意,如果我们用单引号(')替换所有的双引号,这段代码的工作方式完全相同。

向你的武器库引入一种新武器:列表

让我们面对现实吧——打击犯罪是一项艰巨的任务。一个超级英雄(或者伙伴…让我们慢下来,菜鸟!)有时候需要靠的不仅仅是勇敢,主题曲,还有他们与生俱来的超能力。每个值得穿紧身衣的英雄都有某种超级武器或小玩意,当其他一切都失败时,他们可以依靠它们。为此,我们需要开始为你的无用腰带配备更多的工具(它类似于蝙蝠侠的实用腰带,只是,嗯,你的是在跳蚤市场买的)。

我们的第一个小工具是列表。正如变量是数据结构一样,列表也是数据结构。然而,与变量不同,列表可以包含多条数据。变量可以被认为是一个标签或者一个盒子,而列表更像是一个装满一堆盒子的壁橱。

我们可以用存储在变量中的相同数据类型填充列表,包括字符串、数字、整数、浮点数等等。为了给列表赋值,我们将值放在两个square brackets [ ]之间,并用逗号(,)隔开。

让我们创建一个列表:

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']

在这段代码中,我们创建了一个名为 superPowers 的列表,并为其分配了四条独立的信息——在本例中,是字符串值:flight、cool cape、20/20 vision 和 Coding Skillz。

如果我们想打印这个列表,我们所要做的就是使用我们方便的 print()函数:

print(superPowers)

当我们打印这个列表时,有趣的事情发生了——不是像我们期望的那样只打印列表的内容,而是打印整个结构(见图 3-8 ):

img/468718_1_En_3_Fig8_HTML.jpg

图 3-8

打印列表

请记住,列表是一组单独存储的项目。列表中的每一项都对应一个索引号。所有列表都从索引号 0 开始,并在其后按顺序继续。因此,在我们的列表中,“flight”位于 0,“cool cape”位于 1,“20/20 vision”位于 2,依此类推。

例如,如果我们只想打印位于索引号 3 的项目,我们可以这样做:

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']

print(superPowers[3])

这将导致编码 Skillz 打印到屏幕上,因为它位于我们列表的第三个位置(记住,列表从位置 0 开始)。为了更好地理解,让我们分别打印出列表中的每一项:

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']

print(superPowers[0])
print(superPowers[1])
print(superPowers[2])
print(superPowers[3])

图 3-9 向我们展示了结果:

img/468718_1_En_3_Fig9_HTML.jpg

图 3-9

打印列表中的值

或者,您也可以在一行代码中编写 print()函数,如下所示:

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']

print(superPowers[0], superPowers[1], superPowers[2],superPowers[3])

并获得相同的结果。

让我们创建一个文件,并将其命名为 ListExample.py。向其中添加以下代码,然后运行程序(结果如图 3-10 所示):

img/468718_1_En_3_Fig10_HTML.jpg

图 3-10

打印列表中的值的另一种方法

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']

print(superPowers[0], "is located at Index 0")
print(superPowers[1], "is located at Index 1")
print(superPowers[2], "is located at Index 2")
print(superPowers[3], "is located at Index 3")

在这个例子中,我们在 print()函数的末尾追加或添加了一些文本。注意,我们用逗号分隔第一个打印参数,然后定义 print()函数的第二部分。如果我们想在列表中的值之前打印一些文本,我们也可以使用这种方法:

print("The item located at index 0 is", superPowers[0])

这将给我们:位于索引 0 的项目是航班

最后,有一种更简单、更有效的方法来打印出我们列表中的所有项目。让我们创建另一个文件,并将其命名为 PowersWeaknesses.py。

superPowers = ['flight', 'cool cape', '20/20 vision', 'Coding Skillz']
superWeaknesses = ['bologna', 'lactose intolerance', 'social settings', 'tight trunks']

print("Behold our fledgling hero/sidekick, \"Wonder Boy!")
print("His super powers include:", *superPowers)
print("And his weaknesses are:", *superWeaknesses)

使用前面带*符号的列表名称告诉 Python 使用整个列表。例如,如果您键入:print(*superPowers),程序将打印出superPowers列表中的每一项。我们之前代码的结果如图 3-11 所示:

img/468718_1_En_3_Fig11_HTML.jpg

图 3-11

打印列表的全部内容

更改列表

列表和变量一样,可以改变。我们可以给它们添加、删除、重新排列等等。例如,在我们的 PowersandWeaknesses.py 文件中,我们有一个超级弱点列表,其中之一是可怕的“乳糖不耐症”(不能喝乳制品或吃冰淇淋——哦不!).对你来说幸运的是,有一种方法可以消除这种特殊的弱点:他们有药物可以帮助你消化牛奶中的酶。所以现在你又可以用雪糕塞满你的脸了——万岁!

有了这些知识,我们可能想从我们的superWeaknesses列表中删除那个特别的弱点。为了实现这一点,我们将使用del语句。

superWeaknesses = ['bologna', 'lactose intolerance', 'social settings', 'tight trunks']

del superWeaknesses[1]
print(*superWeaknesses)

这将删除位于指数 1 的项目–在我们的案例中为“乳糖不耐受”。当我们把superWeaknesses的内容打印出来的时候,我们现在会看到:博洛尼亚,社交场合,紧身裤。

我们也可以使用 remove 方法从列表中删除一个值。我们没有告诉 Python 该项的位置,而是简单地为它提供了以下值:

superWeaknesses = ['bologna', 'lactose intolerance', 'social settings', 'tight trunks']

superWeaknesses.remove('lactose intolerance')

这将给出与使用del语句相同的结果。

除了从列表中删除项目,我们还可以添加它们。有几种方法可以做到这一点。首先是使用append语句。此方法将项目追加或添加到列表的末尾:

superWeaknesses = ['bologna', 'lactose intolerance', 'social settings', 'tight trunks']

del superWeaknesses[1]

superWeaknesses.append('Taco Meat')

print(*superWeaknesses)

在这个例子中,我们首先创建我们的superWeaknesses列表,然后使用del语句删除位置 1 的项目,就像我们之前做的那样(记住列表从位置或索引 0 开始)。然后我们发现我们有了一个新的敌人——胃绞痛的“玉米卷肉”——所以我们使用append语句将其添加到我们的列表中。当我们打印结果时,我们得到:

博洛尼亚社交设置紧身泳裤玉米卷肉

此外,我们可以将一个项目添加到我们的列表中。insert方法的工作原理与append略有不同。它允许我们在列表中的任何位置添加我们的项目,这里append只是把它放在最后。下面是它在使用中的样子:

superWeaknesses = ['bologna', 'lactose intolerance', 'social settings', 'tight trunks']

del superWeaknesses[1]

superWeaknesses.insert(1,'Taco Meat')

print(*superWeaknesses

insert方法使用两个arguments or 参数。第一个命令告诉 Python 要在列表中添加的项目的位置——也就是说,您希望它在哪个索引位置。第二个参数告诉 Python 您想要向列表中添加什么值。运行前面的代码会打印出:

博洛尼亚 Taco 肉社交设置紧身泳裤

其他列表方法

总共有 11 种方法,数一数,11 种方法。每一个都允许您对存储在列表中的数据执行一些魔法。虽然我们已经回顾了其中的许多,但由于篇幅所限,我们无法在本章中一一介绍。但是,在下面,您可以找到不同列表方法及其用途的表格。作为一项练习,你可以随意尝试。

  • list . pop():pop方法允许您从列表中返回(或打印)一个值,然后删除它。这可让您确认您移除的是正确的项目。示例:

    print(superWeaknesses.pop(1))
    print(*superWeaknesses)
    
    
  • list.reverse():可以对列表中的项目进行排序。一种方法是使用reverse方法。这将改变您的项目的顺序,将第一个项目移动到末尾,最后一个项目移动到前面,以此类推,本质上是颠倒它们的顺序。示例:

    superWeaknesses.reverse()
    print(*superWeaknesses)
    
    
  • list.sort:改变项目顺序的另一种方法是使用 sort 方法。这种方法只是将列表中的项目按字母顺序排序。示例:

    superWeaknesses.sort()
    print(*superWeaknesses)
    
    
  • list.count() : This method is used to count the number of times a given value appears in a list. For instance, you may wish to know how many sidekicks have a weakness for “Taco Meat.” We could figure this out using count. Example:

    print(superWeaknesses.count('Taco Meat')
    
    

    这将返回“Taco Meat”在我们的列表中出现的次数。在这种情况下,只有一次。

  • list.extend():这个方法的使用非常简单。它用于将一个列表合并到另一个列表中。例如,如果你有一个名为“更多超级弱点”的表格,列出了更多可以击败我们英雄的事情,你可以把它和我们以前的列表“超级弱点”结合起来。这样你就只有一个列表需要处理了。示例:

    superWeaknesses.extend(moreSuperWeaknesses)
    
    
  • list.copy() : There are times you may want to copy a list and have a duplicate on hand. Maybe this is for testing purposes, or if you have similarly named data, it would be faster to edit the text than to re-write it. Whatever the case, you can copy a list by using the copy method. Example:

    superWeaknesses2 = superWeaknesses.copy()
    
    

    注意:list.copy 仅在 Python 3.3 及更高版本中可用。使用早期版本的 Python 将导致 AttributeError。

  • list.index():我们经常需要知道一个特定的项目在列表中的位置,以便在需要时调用它。您可以使用index方法在列表中查找一个值的位置,而不是回顾您的代码。示例:

    print(superWeaknesses.index('Taco Meat'))
    
    
  • 将返回数字 3,因为“Taco Meat”在我们的列表中位于第 3 位。(注意:如果你一直在尝试这些方法——特别是分类方法——“玉米卷肉”可能会对你有不同的定位)。

  • list.clear():我们将介绍的最后一个方法是clear方法。我们把这个留到了最后,因为如果你练习使用它,它会做它听起来会做的事情:清除你列表中的任何数据。有时可能需要删除列表中的所有数据——这就是这个方法的用途。示例:

    superWeaknesses.clear()
    
    

在这一集里!

在这激动人心的一集里,我们走了很多路。到目前为止,你的能力正在飞速增长——恕我直言——突飞猛进!很快你就会开着你自己的超级英雄车——也许是神奇的船,或者更好,是神奇的车!

如果你有学习许可证的话。如果没有,那就回到你的神奇循环或神奇溜冰鞋。

让我们回顾一下本章所学的内容,好吗?

  • 注释允许我们记录我们的代码以备将来参考——由我们或另一个程序员。

  • 我们通过使用散列或#和空格来创建注释。之后的任何文本都会被 Python 忽略。

  • 如果我们觉得需要进一步澄清,我们可以在特定的代码行后留下行内注释。请谨慎使用。

  • 注释掉代码有助于我们在不删除现有代码的情况下定位错误。一旦我们确定这不是问题所在,我们只需取消对代码的注释。

  • 转义字符允许您打印通常不会被视为文本的特殊字符。它们还允许你格式化你的字符串。

  • 转义字符包括\t,\n,\ ',\ '和\。

  • 字符串是一种数据类型,可以由字母、数字或符号组成。

  • 您可以使用+ 符号将一个或多个字符串加在一起,称为串联。

  • 您可以使用*符号复制字符串(创建多个副本)。

  • 列表是存储单元,就像一个装满盒子的壁橱;您可以在其中存储许多项,而不是只有一项(在变量的情况下)。你这样定义它们:超能力= ['飞行',' 20/20 视野']等等。

  • 列表包含被索引的项目(数据片段)。这些项目从索引 0 开始,按顺序进行。

  • 您可以通过多种方式打印列表,包括 print(superPowers[1])(针对单个值)或 print(*superPowers),如果您希望打印整个列表。

  • del语句允许你从列表中删除一个项目。

  • 共有 11 种列表方法,包括insert(), append(), pop(), reverse(), sort(), count(), extend(), copy(), index(), clear(), and remove().

四、做决策

当涉及到打击犯罪和处理邪恶(商标待定!),我们这些超级英雄经常发现自己面临岔路口:我们是应该拯救被扔下大楼的无助少女,还是让她一头扎到地上,以便我们能抓住坏人?我们今天要洗我们的斗篷吗?还是我们可以多洗一天,让它闻起来不那么臭?

归根结底,打击犯罪的大部分工作——以及为此而进行的规划——都归结为一件事:做出决策。

你可能听过这样一句话,“每一个动作都有一个反应。”嗯,在编程中尤其如此。想想看:每一次你与计算机接触,你都在强迫它做出决定。当你移动鼠标时,当你按下一个键时,当你因为你的代码不起作用而用头撞击屏幕一个小时时(好吧,也许不是最后一个)——所有这些都需要计算机解释你想要的,并希望执行一个动作。

这里有一个简单的例子:如果你按下字母“a”或字母“k ”,计算机必须知道在这两种情况下该做什么。如果您正在使用文字处理应用,这个特定的场景很简单——将这两个字母中的一个打印到屏幕上。

然而,当我们讨论与计算机编程相关的决策时,我们更多的是指多答案的突击测验。程序会给用户几个选项——例如,选择 A、B 或 C,然后根据选择的选项做出反应。

为了真正理解所有编程中最强大的功能之一,让我们戴上超级英雄的面具,召唤我们的超级大脑,挖掘我们下一个正在发展的超级能力:决策。

做决定

把你的生活想象成一个计算机程序。午餐时间到了,一个初出茅庐的伙伴/即将成为英雄的人需要午餐来保证他/她的肌肉增长。在你面前是一套物品:两片面包、两罐花生酱和三罐果冻。让我们把它列成一个列表,这样我们可以更好地看到它!

  • 面包(两片)

  • 松脆的花生酱

  • 奶油花生酱

  • 苹果果冻

  • 葡萄果冻

  • 草莓酱

正如你所看到的,在你吃午饭之前必须做出决定。我们已经想好了面包,但是我们要用什么类型的花生酱呢?果冻怎么样?

这种场景被称为决策,或者更好的说法是一个条件语句。也就是说,如果满足某些条件,我们/程序将如何反应?为了以编程的方式来看这个,让我们转向一个叫做的伪代码

不,伪代码不是你父母在 20 世纪 80 年代用来即兴演奏的菲尔·柯林斯老歌。这是一种使用听起来像代码但不是的语言来规划代码的方法。如果我们对伪代码应用 or 三明治场景,它看起来会像这样:

if making sandwich, get bread
Then choose peanut butter type;
if peanutButterType = "Creamy"
print "That's gross. Don't be gross."
else print "Crunchy is the correct choice! You win deliciousness!"
Next choose jelly type;
If jellyType = "Grape"
print "You really aren't good at this are you?"
else if jellyType = "Strawberry Jam"
print "Sure, if you want to ruin your peanut butter, go ahead."
else print "Apple Jelly is the only Jelly! The golden nectar of the Gods! You are so wise!"
Next put peanut butter and jelly on bread, smash together, leave the crusts on, and eat.

如果你把代码放到 Python 中,你会得到大量的错误,因为记住,它不是工作代码。它是伪的,意思是假的或嘲弄的。有时在真正编码之前,我们使用伪代码来设计我们的程序,这样我们可以设计出重要的部分。这有助于我们的编程逻辑,并允许我们避免编码中的错误。它可以像你的朋友写下的一套详细说明如何去漫画书店的指南。它可能并不漂亮(尽管一些伪代码很漂亮,充满了图表和图形),但它给了你需要去哪里的想法。

条件语句

用最基本的术语来说,条件语句是决定一段代码是否运行的代码片段——取决于条件是否满足。从编程的角度来看,条件语句可以用在简单的示例中,例如:

如果用户选择成为超级英雄,将他/她输入“英雄”类别;否则,将它们放入反派位置。

  • 如果一个超级英雄通过接触有毒废物获得了他们的超能力,把他们归类为“变异的”如果不是,把他们归类为“继承的超能力”

  • 如果一个超级英雄有悲惨的背景,让他们的性格类型“黑暗和忧郁”否则,让他们的个性“机智风趣”

这些是条件语句最基本的用法。在现实世界中,要执行(或不执行)程序的某个部分,可能需要满足多个条件。我们很快就会进入更高级的类型,但是现在,让我们看看最基本的条件语句:If语句。

请看——If 语句!

前面的例子都是所谓的if语句的一部分。If语句基本陈述了如果某事发生,做这个。这也意味着,如果某件事情没有发生,程序将会做其他事情——这可能意味着程序什么也不做。

为了让事情更清楚,让我们尝试一点代码。创建一个名为ConditionalStataments.py的新 Python 文件,并输入以下代码:

superHeroType="Dark and Brooding"

print("Let's see what sort of hero we have here...")

if superHeroType=="Dark and Brooding":
    print("Ah, it says here you are 'Dark and Brooding'.")
    print("I bet you had a tragic event in your past!")
    print("Your voice sounds pretty rough by the way...")
    print("Here, have a cough drop. Or two.")

这段代码中有几点需要注意。首先,我们创建了一个名为superHeroType的字符串变量,并用一些文本填充它。这个变量中的文本就是我们将要测试的If语句。

在打印一些文本后,我们用下面一行开始 if 语句:

if superHeroType=="Dark and Brooding":

当解释器看到这一行代码时,就进入条件语句,检查是TRUE还是FALSE。如果条件满足,也就是说,结果为真,程序运行剩余的代码,即缩进的(因此是其中的一部分)—if语句。

在这种情况下,条件得到了满足:superHeroType中的文本等于“黑暗和沉思”,因此程序打印出了print()函数,它们是if语句的一部分。既然是这种情况,程序会产生(见图 4-1 ):

img/468718_1_En_4_Fig1_HTML.jpg

图 4-1。

使用条件语句

另一件需要注意的事情是:==符号被称为比较运算符。在这种情况下,这意味着被比较的值必须完全等于前面引号(" ")中的值。我们在评估文本和数字时使用==符号。

但是如果我们的条件不满足会发生什么呢?如果superHeroType的值不等于“黑暗冥思”怎么办?为了找到答案,我们所要做的就是编辑我们的代码来改变它的值并再次运行程序:

superHeroType="Quick-Witted and Funny"

print("Let's see what sort of hero we have here...")

if superHeroType=="Dark and Brooding":
    print("Ah, it says here you are 'Dark and Brooding'.")
    print("I bet you had a tragic event in your past!")
    print("Your voice sounds pretty rough by the way...")
    print("Here, have a cough drop. Or two.")

现在,当我们运行我们的代码时,返回的只是开始的print()函数(见图 4-2 ):

img/468718_1_En_4_Fig2_HTML.jpg

图 4-2。

未被触发的 if 语句的结果

为什么会这样?因为我们改变了我们的superHeroType变量的值,当 Python 遇到我们的if语句时,它检查条件并发现它没有被满足并返回false。由于不满足条件,Python 跳过了if语句块的剩余部分,并转移到程序的下一部分。

由于没有程序的下一部分,Python 退出,程序结束。

当然,我们可以在程序中创建多个if语句。如果我们这样做了,Python 将评估每一条语句并执行代码块,只要满足条件。让我们打开我们的ConditionalStatements.py文件并修改代码,使其与下面的代码相匹配:

superHeroType="Quick-Witted and Funny"

print("Let's see what sort of hero we have here...")

if superHeroType=="Dark and Brooding":
    print("Ah, it says here you are 'Dark and Brooding'.")
    print("I bet you had a tragic event in your past!")
    print("Your voice sounds pretty rough by the way...")
    print("Here, have a cough drop. Or two.")

if superHeroType=="Too Polite":
    print("It says here that you are 'Too Polite'")
    print("How are you ever going to catch that criminal if you keep holding the door?")
    print("Don't say sorry to him - he's the villain!")

if superHeroType=="Quick-Witted and Funny":
    print("Oh boy. I can tell by all the puns that you are the Quick-Witted and Funny Type.")
    print("I have a joke for you:")
    print("What has 8 fingers, two thumbs, and isn't funny?")
    print("You!")

使用这段修改后的代码,我们在程序中添加了三个条件 if 语句,而不是一个。程序首先打印出一些文本,然后遇到第一个 if 语句,该语句检查superHeroType的值是否等于“黑暗和沉思”。因为它不是,我们的程序忽略该块的缩进代码的其余部分。

每当我们有一个带有缩进文本的代码块时,Python 知道缩进的代码属于那个特定的代码组。一旦它用完了缩进的代码,它就知道特定的代码块结束了,并继续下一个代码块。

不要太纠结于代码缩进——我们很快会更详细地讨论它。现在,只需要知道代码块有一个层次结构——也就是一个结构化的顺序——它依赖于缩进(通常是四个空格或一个 tab 键)来表示代码的哪一部分属于哪一部分。

接下来,Python 运行到我们的第二个if语句,并再次检查标准:superHeroType是否等于“太客气”同样,它没有,所以解释器继续下一个代码块,这恰好是我们的第三个 if 语句。

在第三个 if 语句中,我们检查superHeroType的值是否等于“机智幽默”这一次,结果是true,所以解释器执行缩进的print()函数,这些函数是代码块的一部分。结果如图 4-3 所示:

img/468718_1_En_4_Fig3_HTML.jpg

图 4-3。

评估为 True 的 if 语句示例

布尔逻辑和比较运算符

在我们深入研究条件语句之前,我们需要定义一些有趣的词。这些有趣的话不仅可以一遍又一遍地对你的朋友和家人说,而且也是你无用腰带上的另一个便利工具。

第一个字是Boolean。来吧,大声说出来,让笑声远离你的系统。然后,绕着房子跑几圈,看看你能在对话中使用多少次这个词——布尔。我会在这里等。

布尔是另一种数据类型,正如您可能已经从我们之前对ConditionalStatements.py代码的解释中猜到的,这种特殊的数据类型可以有两个不同的值:truefalse

当我们处理像if这样的条件语句时,我们最终会问某个条件是true还是false。无论我们如何描述这些条件或标准,最终,答案只能是这两个选择中的一个。

当然,我们不能只是和计算机玩一个真心话大冒险的游戏,所以 Python(和其他语言)使用一种被称为比较运算符的东西来帮助我们比较数据,并确定最终结果是true还是false

我们已经讨论过比较运算符之一——等于运算符==。除此之外,我们还可以使用其他五种比较运算符。它们如下:

  • ==用于查看一个值是否等于另一个值

  • !=用于查看一个值是否不等于另一个值

  • 用于确定一个值是否大于另一个值

  • < =用于小于或等于另一个值

  • =用于大于或等于另一个值

到目前为止,我们已经在条件语句示例中使用了字符串。为了更好地理解我们的新工具,比较运算符,让我们转而使用数字。首先,创建一个名为 MathIsHard.py 的新文件。

wonderBoyAllowance = 10
newCape = 20

print("That new cape sure is shiny. I wonder if you can afford it...")

if wonderBoyAllowance > newCape:
    print("Congrats! You have enough to buy that new cape!")

if wonderBoyAllowance < newCape:
    print("Looks like you'll have to keep wearing that towel as a cape...")
    print("Maybe if you ask nicely Wonder Dad will give you a raise...")

让我们更仔细地检查一下这段代码,好吗?我们首先创建两个变量:wonderBoyAllowance 和 newCape。然后,我们打印一些文字说,“新的海角肯定是闪亮的。不知你能否负担得起……”

为了弄清楚神奇小子是否真的买得起那件新斗篷,我们必须比较wonderBoyAllowance(代表你的零花钱)和newCape(代表那件闪亮的新斗篷的价格)。

我们的第一个if语句查看wonderBoyAllowance是否为>(或大于 ) newCape。如果是这样,它将打印出文本,“恭喜!你有足够的钱买那件新斗篷!”然而,由于津贴是而不是大于新 cape 的成本,程序跳到下一个if语句,看看它的值是否为真。

当评估第二个if语句时,程序会注意到您的津贴值小于新 cape 的成本。由于该条件得到满足并返回一个值true,它将执行 if 语句的剩余部分,导致(见图 4-4 ):

img/468718_1_En_4_Fig4_HTML.jpg

图 4-4。

评估多个 if 语句

要了解Boolean逻辑是如何工作的,创建一个新的 Python 文件并将其命名为BooleanExamples.py。输入此代码:

# Creating two variables with different values

a=10
b=20

# Compare values using the different Comparison Operators

print("Is the value of a EQUAL to b?  ", a == b)
print("Is the value of a NOT EQUAL to b?  ", a != b)
print("Is the value of a GREATER than b?  ", a > b)
print("Is the value of a LESS than b?  ", a < b)
print("Is the value of a GREATER THAN or EQUAL to b?  ", a >= b)
print("Is the value of a LESS THAN or EQUAL to b?  ", a <= b)

运行这个程序将显示哪些比较是true哪些是false。值true表示比较正确,而false表示不正确。

Else 语句

现在我们已经理解了if语句和比较操作符,我们可以继续讨论另一种类型的条件语句:else。到目前为止,我们已经使用了条件语句,这些语句仅在满足给定条件时才执行一组代码。然而,如果我们想要一个结果,如果结果为真,而另一个结果为假,会发生什么呢?虽然从技术上讲,我们可以使用多个 if 语句来实现这个结果,但是有一种更好、更有效的方法来编写您的程序。让我们编辑我们的MathIsHard.py文件的代码,并对其进行修改,使其与下面的代码相匹配:

WonderBoyAllowance = 10
NewCape = 20

print("That new cape sure is shiny. I wonder if you can afford it...")

if WonderBoyAllowance > NewCape:
    print("Congrats! You have enough to buy that new cape!")

else:
    print("Looks like you'll have to keep wearing that towel as a cape...")
    print("Maybe if you ask nicely Wonder Dad will give you a raise...")

在这个版本中,我们用一个else语句替换了第二个if语句。else 语句只有在if语句的条件不满足时才会被触发。基本上,你对程序说的是,“如果发生这种情况,做这个,否则,做那个。”

这个程序的结果和之前的一样;然而,现在涉及的代码更少了,由于没有第二个 if 语句,Python 不需要执行另一个比较。这节省了计算能力和处理。虽然这在这里看起来没什么大不了的,但是你可以想象在一个程序中,数万行代码和数百条if语句可以节省多少。

还有一点需要注意:当使用一个else语句时,Python 将总是执行你的 if 块或者你的 else 块;如果不走这两条路中的一条,你的程序将永远不会结束。

但是,如果您需要不止一个ifelse选项,会发生什么呢?如果有三个选择呢?还是四个?还是 40 亿?为此,你需要比微不足道的ifelse声明更有力的东西。

你准备好再次升级这些能力了吗?如果是这样(明白了——一语双关!),准备学习——else if

Else If 语句

我知道你在想什么-else if不是一个真正的短语。事实上,这可能是一个整天挤牛奶、擦擦疲惫额头上汗水的农民的名字——叫他埃尔塞夫叔叔吧!

我不想告诉你这个消息,但是 else if 是一个真实的短语,它是条件语句家族中的一员。它是高度通用的,高效的,并且将会是你作为一个程序员最好的朋友之一。有了它,您可以创建任意数量的条件场景,而不是使用常规 if/else 语句的枯燥混合来创建一个或两个常规场景。

像往常一样,学习这种新力量的最好方法是穿上衣服,尝试一下。因此,记住这一点,创建一个名为UncleElseIf.py的全新文件,并插入以下代码:

# Create our variables representing our allowance and the cost of a new cape

wonderBoyAllowance = 20
newCape = 20

print("That new cape sure is shiny. I wonder if you can afford it...")

if wonderBoyAllowance > newCape:
    print("Congrats! You have enough to buy that new cape!")
    print("And it looks like you have some money left over.")
    print("How about getting a hair cut? You hair is covering your mask!")

elif wonderBoyAllowance == newCape:
    print("You have exactly enough money to purchase the cape!")
    print("No change for you!")
    print("Eh...and no tip for me I see...")

else:
    print("Looks like you'll have to keep wearing that towel as a cape...")
    print("Maybe if you ask nicely Wonder Dad will give you a raise...")

这段代码可能看起来很熟悉,因为它是我们的MathIsHard.py文件的修改版本。首先,我们将wonderBoyAllowance的值改为 20(祝贺加薪!);过一会儿你就会明白为什么了。接下来,我们做介绍性的print()语句,接着是第一个if块。这第一个if检查看如果我们的津贴是大于新斗篷的成本。由于该比较返回一个false,程序跳过 print()函数并继续下一个块。

等一下。下一个块根本不是ifelse。事实上,它甚至没有提到else-if——怎么回事?嗯,创造 Python 的大师决定让else-if语句在语言中混合使用 else 和 if,因此是elif

当解释器看到elif时,它再次评估比较——在这种情况下,它检查我们的津贴是否与新斗篷的成本完全相同。因为它是——两个变量都保存值20——其余的 else-if 执行,缩进的print()函数施展它们的魔法。

因为 else-if 的计算结果为 true,所以程序知道没有必要再进一步查看,并从这个特定的代码块中退出。因为在 if/else/else-if 块之后没有代码,所以程序结束。

这就是事情变得有趣的地方。尽管我们将ifelseelse-if称为它们自己的块,但实际上,它们都是同一个块的一部分。想想看:没有elseif就没有else-if,对吗?好吧,你可以,但是那样你的程序可能不会按照你想要的方式运行!

如上所述,else-if语句允许我们创建任意数量的选项。让我们在代码中再添加几个elif并检查结果。修改UncleElseIf.py的文本,使其与以下内容匹配:

# Create our variables representing our allowance and the cost of a new cape

wonderBoyAllowance = 20
newCape = 20

print("That new cape sure is shiny. I wonder if you can afford it...")

# Check to see if allowance is greater than the cost of the new cape
if wonderBoyAllowance > newCape:
    print("Congrats! You have enough to buy that new cape!")
    print("And it looks like you have some money left over.")
    print("How about getting a hair cut? You hair is covering your mask!")

# Check to see if allowance is the same exact price as the new cape
elif wonderBoyAllowance == newCape:
    print("You have exactly enough money to purchase the cape!")
    print("No change for you!")
    print("Eh...and no tip for me I see...")

# Check to see if allowance is zero dollars
elif wonderBoyAllowance == 0:
    print("Oh boy, you are broke!")
    print("Maybe it's time to hang up the cape and grab an apron!")
    print("Time to become...Bag Boy!")

# If all other conditions fail, this else will trigger
else:
    print("Looks like you'll have to keep wearing that towel as a cape...")
    print("Maybe if you ask nicely Wonder Dad will give you a raise...")

在这个版本的代码中,我们在每个部分都添加了注释(#),以使代码片段更加清晰。我们还向我们的条件块添加了第二个elif;它检查wonderBoyAllowance的值是否为 0,如果是,打印出一些文本,建议您获得一份新工作。

理论上,我们可以向这个条件块添加任意多的elif,只要我们满足需要的条件。例如,我们可以以 1 为增量检查 wonderBoyAllowance 的值,直到达到 20。下面是一个例子:

# Create our variables representing our allowance and the cost of a new cape

wonderBoyAllowance = 20
newCape = 20

print("That new cape sure is shiny. I wonder if you can afford it...")

if wonderBoyAllowance == 0:
        print("Nope. You need 20 more dollars.")

elif wonderBoyAllowance == 1:
    print("Nope. You need 19 more dollars.")

elif wonderBoyAllowance == 2:
    print("Nope. You need 18 more dollars.")
elif wonderBoyAllowance == 3:
    print("Nope. You need 17 more dollars.")
elif wonderBoyAllowance == 4:
    print("Nope. You need 16 more dollars.")
elif wonderBoyAllowance == 5:
    print("Nope. You need 15 more dollars.")

# Keep adding elif until you reach 19
# Then use an else for if the value equals 20 or higher

else:
          print("Looks like you have just enough!")

在这个代码示例中,我们添加了 5 个elseif来覆盖你零花钱的前 5 美元。我本来可以增加总共 19 个elseif,但是那会占据这本书的好几页。相反,你可以自由地自己填充空白并测试这个程序。将wonderBoyAllowancenewCape的值交替几次,这样您就可以看到结果是如何根据我们测试条件的变量的值而变化的。

逻辑运算符

尽管elif语句非常强大,但你还需要学习一种能力,才能真正成为条件语句的大师...声明...声明...(这里有回音吗?).这种能力被称为逻辑运算符

*到目前为止,我们已经讨论了许多不同的操作符类型,包括本章前面的比较操作符。只有三个逻辑操作符,但是它们会给你的程序带来全新的能力。

像比较运算符一样,逻辑运算符只有一个目的:帮助您比较不同的值。也像比较运算符一样,逻辑运算符寻求一个布尔答案:真或假。它们主要用于确定两个或更多的比较是真还是假。与我们的其他操作符不同,逻辑操作符不是由特殊字符或符号组成的,而是由不言自明的实际单词组成的:andnotor

其中第一点可能是最容易理解的。它只是查看语句,并尝试确定“这个和那个”是否都为真。如果两者都是,则评估为true;如果不满足一个或多个条件,则评估为false

让我们在代码中更仔细地检查一下。创建名为 LogicalOperatorsExample.py 的新文件,并输入以下代码片段:

# Create a few variables to evaluate

wonderBoyAllowance = 20
newCape = 20
oldCape = 'smelly'

# Check to see if allowance is equal to the cost of a new cape AND
# that the old cape is "smelly"

if wonderBoyAllowance >= newCape and oldCape == 'smelly':
    print("Wow...you can afford to buy a new cape!")
    print("And your old cape IS really stinky!")
    print("Why not treat yourself to a new cape?")

# If the if fails, this else statement will trigger
else:
    print("Sorry kid, it just isn't time for a new cape yet.")

在神奇小子购买新斗篷之前,必须满足两个条件。首先,他必须有 20 美元来支付这笔费用。第二,他的旧斗篷必须有臭味——这是他能证明花毕生积蓄买一件新斗篷是合理的唯一方法!

在设置好要评估的变量后,我们弹出一个if语句来检查wonderBoyAllowance是否大于或等于newCape的值(>=)。在这种情况下,它等于,所以解释器继续前进,看到and操作符,并且知道下一部分求值必须也是才能使整个if语句求值为true。它检查oldCape的值是否等于“发臭”——事实的确如此!–由于两个条件都是true,它继续打印出if语句的剩余部分。

如果这两个条件中的任何一个不为真,那么就会触发else语句。

下面是结果(图 4-5 ):

img/468718_1_En_4_Fig5_HTML.jpg

图 4-5。

使用 else 语句

逻辑运算符列表中的下一个是 or。当用于条件语句时,or 运算符要求至少有一个条件的计算结果为真,其他条件可以为假,但只要有一个条件为真,整个语句的计算结果为真。

下面是一个 or 运算符的例子:

# Variables to check

wonderBoyAllowance = 20

newCape = 20
newShoes = 50

# Checks if you can afford a new cape OR if you can afford new shoes

if wonderBoyAllowance >= newCape or wonderBoyAllowance >= newShoes:
    print("Looks like you can either afford a new cape or new shoes.")
    print("That's good, because one of them are really stinky!")

# If both of the conditionals fail, the else below triggers
# If even one of the conditionals are true, the else does not trigger

else:
    print("That's a shame, because one of them is really stanky!")

该示例程序旨在检查一个或两个条件是否为true。如果两者都是true,很好——我们的print()功能仍然触发。如果只有一个条件是true——仍然很棒;我们的print()功能将会触发。记住:一个or操作符只需要一个条件为true

只有当条件都不满足时,程序才会触发else语句。

敏锐的观察者可能会注意到这些程序的一个小问题——虽然我们知道神奇男孩可以买得起一双鞋或一件新斗篷,但我们不知道他会选择哪一件。更进一步,我们不知道他是否能一起负担得起这两者;我们只是看看他是否能负担得起其中任何一个。

有几种方法可以解决这个问题并扩展我们的计划。我们可以添加一些 if 语句来解决问题。然而,现在可能是讨论所谓的嵌套的好时机。不,这和鸟没有任何关系!

筑巢——不仅仅是为了鸟类

有时,检查给定块中的一个(或两个)条件是否为真是不够的。例如,我们可能希望检查第二个或第三个(或第四个等等。)条件满足如果第一个评估为真。考虑一下我们的代码,它决定了神奇小子是否可以购买新的斗篷和鞋子。我们知道神奇小子可以购买其中任何一个,但我们不知道他是否有足够的钱来购买这两个。我们也不知道他更需要哪一个——斗篷还是鞋子。

我们可以通过编程来回答其中的一些问题——也就是说,我们可以使用我们的程序来解开这些答案。当我们在一个 if 中检查多个语句时,我们称之为嵌套。

到目前为止,您已经注意到当我们使用 if 语句时,代码是如何自动缩进的;在我们插入一种颜色(:)并按 enter 键后,开发环境跳过一行,然后缩进八个空格。作为程序员,这直观地告诉我们,缩进的代码是它上面的 if 语句的一部分。它也告诉解释者同样的事情。这就是所谓的代码层次结构,它表示(1)在该代码之前执行该代码,以及(2)该缩进的代码属于它上面的代码。

为了更好地理解嵌套的工作原理,让我们重新看一下前面的例子:

# Variables to check
wonderBoyAllowance = 20
newCape = 20
newShoes = 50

# Checks if you can afford a new cape

if wonderBoyAllowance >= newCape:
    print("You can afford a new cape.")
    print("But how about new shoes?")

# When the if check to see if you can afford the new cape passes it does this

    if wonderBoyAllowance >= newShoes:

        print("Looks like you can afford new shoes as well.")
        print("That's good, because the old ones are really stinky!")
        print("But can you afford both together?")

#If you cannot afford the shoes, but can afford the cape

, it does this
    else:
        print("You can only afford the new cape, sorry.")

# If both of the conditionals fail, the else below triggers
# If even one of the conditionals are true, this else does not trigger

else:
    print("That's a shame, because one of them is really stanky!")

在更新的示例中,首先要注意的是我们的if语句的缩进。第一个if检查神奇小子是否买得起新斗篷。因为他可以(意味着wonderBoyAllowance大于或等于newCape,所以程序继续执行缩进的或者嵌套的if语句。程序再次检查嵌套的if语句的条件是否为true(是否wonderBoyAllowance等于或大于newShoes)。如果是,它将执行缩进的print()函数。

注意

注意,即使是嵌套的 if 语句下的 print()函数也会缩进。

在这种情况下,我们的嵌套的if语句不等于true,所以嵌套的else语句——缩进的语句——触发。

只有当原始的if语句返回一个false时,底部的else语句才会被触发。这个节目的结果?

     You can afford a new cape.
But how about new shoes?
You can only afford the new cape, sorry.

如果有两个以上的 if 语句会发生什么?出现这种情况时,必须对每个附加的 if 语句使用 elif。让我们用一个简单的数学例子来真正说明嵌套 if 语句的威力。创建一个名为 SuperHeroQuiz.py 的新文件,并键入以下代码:

# Variable representing Wonder Boy's Test Score

wonderBoyScore = 100

# Introduction text

print("Congratulations on finishing your Super-Hero Quiz Intelligence/Reasoning Test.")
print("Or, S.Q.U.I.R.T. for short.")
print("Let's see if you passed or failed your exam!")
print("A passing grade means you are licensed to be a Sidekick!")

# Comparison block to see if Wonder Boy passed his S.Q.U.I.R.T. Exam

if wonderBoyScore > 60:
    print("Here are your results: ")

    if wonderBoyScore > 60 and wonderBoyScore < 70:
        print("Well, you passed by the skin of your teeth!")

    elif wonderBoyScore >= 70 and wonderBoyScore < 80:
        print("You passed...average isn't so bad. I'm sure you'll make up for it with heart.")

    elif wonderBoyScore >= 80 and wonderBoyScore < 90:
            print("Wow, not bad at all! You are a regular B+ Plus player!")

    elif wonderBoyScore >= 90:
            print("Look at you! Top of your class. Yer a regular little S.Q.U.I.R.T. if I ever saw one!")

else:
        print("Nice try fella, but I'm sorry you didn't pass.")
        print("I hear the Burger Blitz needs a security guard - you are a shoo-in!")

在这种情况下,神奇小子还不是一个成熟的伙伴。为了成为其中之一,他/你必须通过 S.Q.U.I.R.T .考试。只有高于 60 分的分数才表明及格。

除了弄清楚神奇小子是否通过了考试,我们还想给他一点关于他考试成绩的反馈。对于每一个 10 分的范围,我们创建了一个if/elif语句,该语句将根据分数显示一些文本。

如果神奇小子没有通过考试(他的分数在 60 分或以下),所有嵌套的if/elif语句将被跳过,取而代之的是else语句将被触发。

一个重要的注意事项:如果第一个if语句条件不满足,其他条件都不会被计算;相反,程序会自动跳到else语句。当程序运行到第一个if语句时,它检查wonderBoyScore的值,并询问它是否大于 60。如果是而不是,程序将结束并执行else语句。

但是,由于wonderBoyScore 是大于 60 的,程序转到下一个if/elif语句对其求值。它继续这个过程,直到找到一个评估为true的条件。

该方案的结果是:

Congratulations on finishing your Super-Hero Quiz Intelligence/Reasoning Test.
Or, S.Q.U.I.R.T. for short.
Let's see if you passed or failed your exam!
A passing grade means you are licensed to be a Sidekick!
Here are your results:
Look at you! Top of your class. Yer a regular little S.Q.U.I.R.T. if I ever saw one!

随意更改几次wonderBoyScore的值,然后重新运行程序,看看结果如何变化。

在这一集里!

这激动人心的一集充满了动作。在迄今为止的所有章节中,我敢说这一章提升了你的能力最多!有很多东西要塞进一集(有点像你如何把所有的果冻塞进你的 PB&J,并希望它不要溅到你的衬衫上),但凭借你的超级大脑,敏锐的洞察力,以及阅读陈腐的超级英雄笑话的能力,我敢肯定你会吸收这个坟墓中包含的所有信息。

你会用它行善还是作恶?只有时间会证明一切!

当你的父母询问这本书的迷人之处时,你可以和他们分享一下,这本书是由了不起的作家詹姆斯·佩恩写的,为什么你不能停止阅读它!

  • 决策是一个程序必须根据某些定义的标准决定选择一条或另一条道路的过程。

  • 伪代码是一种用来描述程序部分的虚构语言;这是一种对程序进行布局的简写,以便更好地理解程序的布局和不同部分。

  • 如果满足/不满足某些条件,条件语句允许你的程序沿着程序的一个分支或另一个分支前进。它们包括ifelseelif语句。

  • 语句允许你在程序中创建决策。例如,如果发生了“x ”,你可以让程序执行一段代码

    Example:

    if 10 < 20:
        print("Yes, 10 is less than 20")
    
    
  • Else 语句通过添加 else 子句来增强 if 语句。例如,如果“x”发生,你可以让一个程序执行一段代码,或者如果“x”没有发生,你可以让它执行不同的代码块。**

    Example:

    if 10 < 20:
        print("Yes, 10 is less than 20")
    else:
        print("Maths are hard! Numbers bad for brain!")
    
    
  • Else if/elif 语句用于向代码中添加额外的 if 条件。

    Example:

    if 10 < 20:
       print("Yes, 10 is less than 20")
    elif 10 == 20:
       print("10 shouldn't be equal to 20, but if you say!")
    else:
        print("In our backwards world, 10 is greater than 20!")
    
    
  • 比较运算符允许您比较值。分别是:等于(==),不等于(!=)、小于()、小于或等于(<=), and greater than or equal to (> =)。

  • 逻辑运算符允许您检查多个条件。分别是:andnotor。*

五、循环和逻辑

有时候打击犯罪会让你觉得自己在兜圈子。日复一日,你似乎不得不处理相同的斗争:这里的银行抢劫犯,那里的一只困在树上的猫,一个邪恶的天才试图接管宇宙。这就好像你陷入了某种…循环。

虽然被困在众所周知的土拨鼠日——这一天一遍又一遍地重复,比利·穆雷主演的优秀电影《问你的父母》——是一件坏事,但在你的计算机程序中使用loops可能是一件伟大的事情。计算机程序的主要目的之一是日复一日地重复重复性的任务。我们用来奴役我们的程序并让它们执行这些乏味任务的方法之一就是所谓的循环。

正如您现在可能已经猜到的,当某个条件为true时,循环会导致代码片段一遍又一遍地重复。就像条件语句一样(在第四章中介绍),循环需要满足或不满足一个条件,以便执行或不执行,这取决于程序员的需要。

有几种类型的循环,我们将在这非常冒险的一章中讨论每一种类型。所以准备好你自己吧,年轻的英雄——因为我们正准备变得疯狂!

什么是循环?

作为程序员,我们的总体目标之一是高效地编写代码。我们所做的一切都应该以提供良好的用户体验、减少处理器资源和用尽可能少的代码创建程序为中心。实现这一点的一种方法是使用循环,Python 中有两种类型的循环。正如本章介绍中所述,循环是一种神奇的生物,只要满足我们定义的条件,它就允许我们将一段代码重复任意次。

循环在编程中如何工作的一个例子是,如果你创建了一个应用,其中有人必须猜出你在想的数字。代码会一直让用户猜一个数字,直到他们猜对为止,这时循环会退出,程序的其余部分会执行。

一如既往,让我们进入不祥的危险房间!测试一些新的代码。首先,创建一个名为 SinisterLoop.py 的文件,并添加以下代码:

# Create an empty variable. We will store data in it later.

numberGuess = ''

# create a while loop that continues until the user enters the number 42

while numberGuess != '42':
    print("Sinister Loop stands before you!")
    print("I'll only let you capture me if you can guess the number in my brain!")
    print("Enter a number between 0 and 4 gajillion:")
    numberGuess = input() # Stores the number the user types into numberGuess

print("Sinister Loop screams in agony!")
print("How did you guess the number in his head was " + numberGuess + "?")

在这个代码片段的场景中,邪恶险恶的循环面对我们的英雄,神奇男孩,并迫使他猜测坏人心中的恶意数字。如果神奇小子成功了,邪恶循环将允许你抓住他。如果不是呢?好吧,如果不是,那么他会一遍又一遍地不停地让你输入一个数字。好玩吧。

在这个代码示例中,我们学到了一些新东西。我们首先做了一些迄今为止还没有做过的事情——我们创建了一个名为numberGuess的空白(或空)变量。我们将这个变量留空,因为我们将让用户稍后用数据填充它。

接下来,我们创建一个称为while循环的代码块。该行:

while numberGuess != '42':

告诉程序运行,而变量numberGuess的值不等于!=为“42”。然后我们打印几行文本,最后请求用户输入一个数字。存储数字的实际行在代码中:

numberGuess = input()

input()函数类似于 print()函数,只是它接受来自用户的输入或数据。这种输入是通过用户键盘上的按键来收集的。这些击键存储在赋值操作符(=)左边的变量中——在本例中是numberGuess

继续运行代码,输入不同的数字几次,最后输入数字 42,看看程序在运行。

都鬼混完了?很好。简要说明:在这个例子中,我们使用了不等于(!=)操作符作为我们的while标准。您可能会问自己,为什么我们没有使用等于或操作符。原因是因为我们希望程序循环——或者迭代——当某事不为真时。如果我们使用一个来代替,并要求程序在值等于 42 时循环,我们将会产生一个严重的循环逻辑错误。

这就是循环变得危险的地方。如果我们告诉程序在变量值等于 42 时循环,程序根本不会执行我们的循环。为什么呢?因为我们告诉它在 numberGuess 等于 42 时循环。但是,请记住:我们从不设置 numberGuess 的值。因此,当 Python 去检查值是否为 42 时,它确定它不是,并退出循环,因为它只会在值为 42 时循环!

如果您认为这很棘手,请考虑以下情况:如果我们将 numberGuess 的值设置为 42,并将 while 循环条件保持为==42,会发生什么情况?

在这种情况下,程序将永远循环下去。为什么呢?因为我们告诉它“当 numberGuess 的值是 42 时,遍历这段代码。”这就是众所周知的可怕的无限循环,它是每个程序员生存的祸根。为了好玩,让我们创建一个名为 InfiniteLoop.py 的新文件,并输入以下代码:

注意

当你运行这个程序时,会出现一个无限循环。退出它,你将不得不关闭你的空闲窗口,并重新启动空闲。

# Create a variable with the value of 42.

numberGuess = 42

print("Sinister Loop stands before you!")
print("Behold my infinite loop!")

# create a while loop that continues while the value of numberGuess is 42.

while numberGuess == 42:
    print("Loop!")

运行代码看看会发生什么。恭喜——你创建了你的第一个无限循环!现在,再也不要这样做了!

让我们尝试一些不同的东西。让我们用文本代替数字来表示我们的值。创建另一个名为WonderBoyPassword.py的新文件,并键入以下代码:

# create a variable to hold Wonder Boy's password

password = ''
print("Welcome to Optimal Dad's Vault of Gadgets!")

while password != "wonderboyiscool2018":
    print("Please enter your password to access some fun tech!")
    password = input()

print("You entered the correct password!")
print("Please take whatever gadgets you need!")
print("Don't touch the Doom Canon though - that belongs to Optimal Dad!")

这段代码的运行很像你所期望的那样。就像我们使用数字'42'的例子一样,这个程序创建一个空变量并打印出一些介绍性的文本。然后我们创建一个while循环,该循环被设置为运行,直到password的值不等于到“wonderboyiscool2018”。一旦用户输入了这个特定的值,程序就退出循环,转到其他的print语句。

然而,这里有一点小小的不同。因为我们使用的是文本而不是数字数据类型,所以输入的值必须与条件完全相同。也就是说,密码必须包含准确的文本“wonderboyiscool2018”。大写字母必须大写,小写字母必须小写。

这是为什么呢?不要陷入太多无聊的细节,要知道程序中的每个字符都有一个特定的赋值。记住,计算机看不到文本,而是一系列被翻译成机器语言的 1 和 0。正因为如此,计算机将“H”和“H”视为两个独立的事物。

运行该程序,并在提示时尝试键入“WonderBoyIsCool2018”或“WONDERBOYISCOOL2018”,然后观察会发生什么。

如你所见,程序继续while循环,并不断要求输入密码。只有输入“wonderboyiscool2018”程序才会退出循环。

用这种类型的“循环逻辑”编写循环代码是完全正常的。事实上,当涉及到密码或安全信息时,这正是程序应该表现的方式。但是如果你不关心大写字母呢?如果您希望投入无论如何资本化都能发挥作用呢?

有几种方法可以实现这一点。其中之一是将文本转换成小写字母。为此,您可以使用一个名为 str.lower()的新字符串函数。更改 WonderBoyPassword.py 的代码,使其符合以下内容:

# create a variable to hold Wonder Boy's password

password = ''
print("Welcome to Optimal Dad's Vault of Gadgets!")

while password != "wonderboyiscool2018":
    print("Please enter your password to access some fun tech!")
    password = input()
    password = password.lower()
print("You entered the correct password: ", password)
print("Please take whatever gadgets you need!")
print("Don't touch the Doom Canon though - that belongs to Optimal Dad!")

在这段代码中,我们在前面的代码片段中添加了新的一行:

password = password.lower()

这行代码获取变量password中的数据,并将其转换成小写。这样,当循环检查密码是否正确时,它不需要担心用户是否输入了大写字母。

注意

要使整个字符串小写,可以使用str.lower()

例如:password.lower()

要使字符串大写,可以使用str.upper()

例如:password.upper()

极限环

虽然我们可以允许循环无限期地执行,但我们常常希望限制它们运行的次数。例如,在我们的WonderBoyPassword.py代码中,我们允许用户想猜多少次就猜多少次;只有给出正确的密码,程序才会退出。然而,这可能不是编写这样一个程序的最佳方式。

当处理密码时——或者当您需要限制循环执行的次数时——您可以创建一个条件,使循环在满足给定标准时break

要查看使用中的break,编辑WonderBoyPassword.py中的代码,使其与以下代码匹配:

# create a variable to hold Wonder Boy's password

password = ''

passwordAttempt = 0

print("Welcome to Optimal Dad's Vault of Gadgets!")

while password != "wonderboyiscool2018":
    print("Please enter your password to access some fun tech!")
    password = input()
    password = (password.lower())
    passwordAttempt = passwordAttempt + 1

    if password == "wonderboyiscool2018":
        print("You entered the correct password: ", password)
        print("Please take whatever gadgets you need!")
        print("Don't touch the Doom Canon though - that belongs to Optimal Dad!")

    elif passwordAttempt == 3:
        print("Sorry, you are out of attempts!")
        break

在这个版本的WonderBoyPassword.py中,我们增加了几行新代码。首先,我们定义了一个名为passwordAttempt的新变量,并赋予其值0。该变量将用于跟踪猜测密码的尝试次数。每次用户猜错了,循环就会重复,多亏了这段代码:

passwordAttempt = passwordAttempt + 1

1加到passwordAttempt的值上。然后我们添加了两个if语句。如果用户猜出了正确的密码,第一个会打印出一些文本。一旦passwordAttempt的值等于 3(尝试三次后),el if语句就会触发。一旦被触发,它打印出一些道歉文本,然后使用break语句退出while循环。

试着输入几次密码,确保至少三次猜错密码,至少一次猜对密码。

对于循环

另一种确保循环只迭代一定次数的方法是使用for循环。当您知道想要重复一段代码多少次时,通常会使用这种类型的循环。引入 for 循环的一种流行方法是创建一个程序,通过一系列数字进行计数——比如 1-10。然而,我们不是普通的程序员——我们是碰巧编码的超级英雄。因此,我们需要一种特殊类型的程序。看看邪恶的恶棍!Count10.py 的例子!

print("Sinister Loop, I know you are in there!")
print("If you don't come out of the cafeteria freezer by the time I count to 10...")
print("You won't get any of that delicious stop-sign shaped pizza!")

for x in range(1,11):
    print(x)

print("I warned you! Now all the pizza belongs to Wonder Boy!")

这段代码的重要部分出现在这里:

for x in range(1,11):
    print(x)

for开始循环。'x'是一个变量(你可以随意命名这个变量;传统上程序员将其命名为‘I’或‘x’),它们将保存迭代次数的值。事实上,当这样使用时,它被称为一个迭代变量。接下来,我们使用range函数告诉循环要使用的序列。一个序列可以由一个数字范围组成,也可以使用文本(下面将详细介绍)。

range后面括号中的数字是函数的startstop参数。对于我们的例子,我们想数到 10,所以我们把开始放在 1,停止放在 11。我们在这里选择使用 11,尽管我们希望范围在 10 处停止,因为范围在我们的终点之前的数字处停止。如果我们想让阴险的循环有很长的时间从冰箱里出来,我们可以在 0 点开始,在 10 点停止,或者在 12 点开始,在 1,000,000 点停止。).

最后,我们print(x)打印出迭代发生的次数。一旦到达‘10’,程序breaks从 for 循环跳到代码的下一部分,这恰好是最后一条打印语句。

如果您运行该程序,您会得到以下结果:

Sinister Loop, I know you are in there!
If you don't come out of the cafeteria freezer by the time I count to 10...
You won't get any of that delicious stop-sign shaped pizza!
1
2
3
4
5
6
7
8
9
10
I warned you! Now all the pizza belongs to Wonder Boy!

如果我们想让代码更有趣一点,我们可以向属于for循环的print语句添加一些文本,如下所示:

print("Sinister Loop, I know you are in there!")
print("If you don't come out of the cafeteria freezer by the time I count to 10...")
print("You won't get any of that delicious stop-sign shaped pizza!")

for x in range(1,11):
    print(x, "Mississippii")

print("I warned you! Now all the pizza belongs to Wonder Boy!")

我们所做的只是改变:

    print(x)

    print(x, "Mississippii")

这给了我们一个新的结果:

Sinister Loop, I know you are in there!
If you don't come out of the cafeteria freezer by the time I count to 10...
You won't get any of that delicious stop-sign shaped pizza!
1 Mississippii
2 Mississippii
3 Mississippii
4 Mississippii
5 Mississippii
6 Mississippii
7 Mississippii
8 Mississippii
9 Mississippii
10 Mississippii
I warned you! Now all the pizza belongs to Wonder Boy!

我们在这里所做的只是将单词“Mississippii”添加到迭代循环之外的输出中。

除了向上计数,range 还有向下计数的能力。为了实现这一点,我们需要使用一个叫做step的东西。Steprange()的可选参数,用于向上或向下“步进”数字。例如,如果我们想从 10 倒数到 1,我们将编写一个如下所示的 For 循环:

for x in range(10,0, -1):
print(x)

循环的-1部分是step,基本上是告诉程序每次减一。如果您运行此代码,将会导致:

10
9
8
7
6
5
4
3
2
1

如果我们做了step -2,倒计时会每次减 2。

for x in range (10,1 -2):
print(x)

那么结果将是:

10
8
6
4
2

如果我们想以 2 为增量递增计数,我们不需要添加+ 符号——我们只需将step添加为2,如下所示:

for x in range(1,10,2):
    print(x)

这将产生:

1
3
5
7
9

For 循环更有趣

当然,打印出数字并不是我们使用for循环实现的唯一事情。如上所述,任何时候我们知道我们想要循环通过代码的次数,一个for循环是我们最好的选择。

例如,也许我们想变得令人讨厌,在屏幕上打印一大堆相同的文本。我们的朋友for loop 可以帮上忙!

for x in range(1,10):
    print("Wonder")

print("Boy!")

在退出循环并以“Boy!”结束之前,这个小片段将打印出文本“Wonder”九次。如果你把一些很酷的主题音乐放在后面,你就可以为你自己的电视连续剧做好准备了!

我们使用for循环的另一种方式是遍历列表。假设我们有一个邪恶恶棍的列表,我们想打印出他们的名字。我们可以使用类似这样的代码:

nefariousVillains = ['Sinister Loop', 'The Pun-isher', 'Jack Hammer', 'Frost Bite', 'The Sequin Dream']

print("Here is a list of today's villains, brought to you by:")
print("Heroic Construction Company. You destroy the city, we make it almost, sort of new.")
print("Villains Most Vile:")

for villains in nefariousVillains:
    print(villains)

在这里,我们创建了一个list(我们最初在第三章中讨论过列表,你应该还记得)。然后我们用各种小人填充了list。接下来,我们打印出一些文本,然后进行我们的for循环:

for villains in nefariousVillains:
    print(villains)

这一次,for从创建一个变量名villains开始,它的工作将是保存(临时)我们的list中每个值的值。由于我们没有设置range,循环将对nefariousVillains list中的每个值执行一次。每次都会给villains变量分配一个不同的值。例如,第一次通过循环时,'Sinister Loop'被传递到villains然后被打印。然后循环第二次继续,并通过'The Pun-isher'villains,再次打印。这一直持续到循环运行完list中的所有值。villains中的最终值将是'The Sequin Dream'。它的值将保持不变,直到您更改数据。

如果我们运行这段代码,结果将是:

Here is a list of today's villains, brought to you by:
Heroic Construction Company. You destroy the city, we make it almost, sort of new.
Villains Most Vile:
Sinister Loop
The Pun-isher
Jack Hammer
Frost Bite
The Sequin Dream

中断、继续和传递语句

尽管循环被用来遍历部分代码,但有时我们可能会发现我们需要一种方法来提前结束循环,跳过循环的一部分,或者处理一些不属于循环的数据。在这些努力中,有三个陈述可以帮助我们。

我们早先了解过break;有了这个语句,我们可以在某些条件发生的情况下尽早退出循环。例如,在我们的WonderBoyPassword.py程序中,我们使用break在输入密码三次后退出程序。因为我们之前已经讨论过这个语句,所以让我们继续讨论continue语句。

break语句一样,continue语句让你跳过一个循环的一部分,而不是完全跳出它。考虑一下:如果你有一个从十开始倒数的程序,但是在中途你想打印一些文本;你可以通过continue来实现这个目标。

让我们创建一个名为 DoomsdayClock.py 的新文件。在这个程序中,险恶循环已经启动了一个倒计时定时器,它将发出你的…嗯,厄运的信号。但是,反派总是那么啰嗦,如果他在倒计时的某个时刻有话要说,千万不要惊讶!

将此代码输入您的文件:

print("The nefarious Sinister Loop stands before you, greedily rubbing his hands together!")
print("He has his hand on a lever and has a large grin on his face.")
print("Sinister Loop opens his mouth and says:")
print("'You are doomed now Wonder Boy!'")
print("'You have ten seconds to live! Listen as I count down the time!'")

for x in range(10,0,-1):
    print(x, "Mississippii!")

# When x is equal to 5, print some text, then continue with the count down.

    if x==5:
        print("'Any last words, Wonder Boy?!?'")
        continue

print("You wait for your inevitable doom as the count reaches 0...")
print("But nothing happens!")
print("Sinister Loop screams, 'Foiled Again!'")

运行示例并观察结果,结果应该是这样的:

The nefarious Sinister Loop stands before you, greedily rubbing his hands together!
He has his hand on a lever and has a large grin on his face.
Sinister Loop opens his mouth and says:
'You are doomed now Wonder Boy!'
'You have ten seconds to live! Listen as I count down the time!'
10 Mississippii!
9 Mississippii!
8 Mississippii!
7 Mississippii!
6 Mississippii!
5 Mississippii!
'Any last words, Wonder Boy?!?'
4 Mississippii!
3 Mississippii!
2 Mississippii!
1 Mississippii!
You wait for your inevitable doom as the count reaches 0...
But nothing happens!
Sinister Loop screams, 'Foiled Again!'

这段代码像我们的其他for循环一样工作,有一点例外。一旦程序命中我们的if语句,它就会检查'x'是否等于5。由于我们将range设置为以-1 的增量从 10 递减计数到 0,我们知道在代码重复第五次左右'x'将等于 5。当它出现时,我们的条件得到满足,我们打印出文本“Any last words Wonder Boy?!?”,有效地暂停了一会儿循环(实际上,我们跳过了一次迭代,以便我们可以打印一些文本),然后再次进入循环。

continue语句之后,程序完成其正常循环,然后正常退出程序。

如果您查看结果,请注意行'5 Mississippi'从未打印出来。记住,这是因为我们跳过了循环,所以它不会打印那一行。

到目前为止,我们已经了解了如何在特定条件适用时退出循环,或者如何跳过循环中的一次迭代(分别使用breakcontinue,)。我们学到的下一个说法看起来没那么有用,但是,事实上,它确实在事物的大计划中服务于一个目的。

pass语句在处理称为classes的东西时特别有用——这是我们将在第八章讨论的主题。然而,就循环而言,pass 语句主要用作占位符。当你在计划一段代码,但不完全确定你的标准是什么时,这是一个很好的工具。

例如,在我们的DoomsdayClock.py程序中,我们在循环中放置了一个 if 语句,以便在变量的值为 5 时执行一些文本。然而,如果我们不确定我们想要的文本是什么,或者在倒计时中我们想要将文本打印到哪里,该怎么办?也许我们在等待同事的反馈,然后不得不回到那段代码。

pass语句可以让我们放置条件,而不用定义如果满足条件会发生什么,也不用担心因为没有完成代码而出错。这样,以后,当我们弄清楚我们希望在循环的这一部分发生什么时,我们可以在以后填充其余的代码。

如果我们将pass语句插入到我们的DoomsdayClock.py程序中,它看起来是这样的:

print("The nefarious Sinister Loop stands before you, greedily rubbing his hands together!")
print("He has his hand on a lever and has a large grin on his face.")
print("Sinister Loop opens his mouth and says:")
print("'You are doomed now Wonder Boy!'")
print("'You have ten seconds to live! Listen as I count down the time!'")

for x in range(10,0,-1):
    print(x, "Mississippii!")

# When x is equal to 5, print some text, then continue with the count down.

    if x==5:
        pass

print("You wait for your inevitable doom as the count reaches 0...")
print("But nothing happens!")
print("Sinister Loop screams, 'Foiled Again!'")

如果您运行这段代码,您将会看到当到达if语句时什么也没有发生——程序只是正常运行。然而,如果您要从语句中删除pass,您将会收到一个错误,因为 Python 期望更多的代码来完成if语句。自己试试看吧!

在这一集里!

我们在这一章里讲了很多,如果你觉得有点…糊涂,我不会责怪你。虽然这一章可能是迄今为止最难理解的,但好消息是,一旦你掌握了循环的使用,你就真的拥有了创建一些像样的真实世界程序所需的所有工具。

当然,你可能无法作为世界上最伟大的程序员——简称 WGP——走进办公室,得到一份高薪工作,但是,嘿,你还是个青少年;你已经远远领先于未来竞争的趋势。另外,别忘了,还有整整九章呢!

在这本书的这一点上,你应该对自己的涉猎和创建自己的代码片段和迷你程序感到舒适。像生活中的任何事情一样,熟能生巧,所以一定要经常测试你的新超能力。你编码得越多,你就越能理解编程。

说到这里,在下一章中,我们将会很好地运用我们到目前为止所学的一切,因为我们创建了我们的第一个完整的程序!它将被称为超级英雄生成器 3000,它将包含循环、变量、if-else 语句、字符串和数学函数等等;邀请你的朋友,你将是聚会的灵魂!

至于这一章,让我们在这一集参考页中快速回顾一下我们在中学到的内容!

  • 如果满足/不满足给定的条件,循环允许您重复(也称为迭代)部分代码。

  • For 循环可用于在不满足条件时或通过使用 range 函数进行迭代。例如:

    for x in range(1,10):
       print("Wonder Boy is here!")
    
    
  • Range()是一个函数,它允许你在一个循环中迭代一定的次数。它有三个参数,定义如下:

    range(1, 10, 1)
    
    

    第一个数字是起点。第二个数字是终点。第三个数字是可选的,称为步长,控制 range()计数的增量。例如,对步长使用 2 将在循环中每次迭代增加 2 个数字。

  • 只要满足条件或标准,或者计算结果为布尔值 true,While 循环就会重复。例如:

         salary = 0
    while salary < 10:
         print("I owe, I owe, so off to work I go.")
         salary = salary +1
    
    
  • 无限循环是有害的,大多数时候应该避免。当您的循环编程逻辑有缺陷或者犯了一个错误时,它们就会发生。它们是永无止境的循环——就像一堂糟糕的代数课。这里有一个例子(孩子们,不要对他这么做!):

    x = 0

    while x == 0:

    print:("You down with L-O-O-P?")

    print("Yeah, you know me!")

    由于变量 x 等于 0,并且准则说当 x 等于 0 时循环,这个循环将永远继续下去。

  • Str.lower()是一个将字符串转换成小写的函数。例如:

    name = "Wonder Boy"
    print(name.lower())
    
    

    会用小写字母印刷“神奇小子”。

  • Str.upper()的工作方式与 str.lower()相同,只是它将字符串中的所有字母都改为大写。示例:

    name = "wonder boy"
    print(name.upper())
    
    
  • 如果满足某个条件,并且您希望循环提前结束,break 语句会强制循环退出(或中断)迭代。

  • continue 语句允许您跳过循环中的迭代,而不完全退出循环。

  • pass 语句是一种占位符,允许您创建循环,而不必在循环中定义某些条件,直到以后。通过这种方式,您可以创建循环结构,并决定以后的标准,而不会在测试代码时收到错误。

六、利用我们所学的知识

你已经走了很长一段路了。当你犯了一个不幸的错误,试图抓住他的微波比萨饼咬,你开始被一个放射性程序员咬。从那时起,你的力量开始绽放,你证明了自己是一个值得的伙伴。但是现在是真正考验你的知识和你的 l33t cod3r skillz 的时候了。你准备好迎接挑战了吗?

在这一章中,我们将回顾到目前为止你所学的一切,并将其用于创建你自己的全长程序。此外,你还将学习一些新的技巧,到本章结束时,你将从忠实的跟班升级为成熟的英雄。

你仍然是神奇小子,但至少你不用再给神奇爸爸擦鞋了!

创建你的第一个真正的程序

在我们开始创建我们的第一个全功能应用之前——我们将把它命名为超级英雄生成器 3000——我们必须首先了解我们到底希望程序做什么。基本概念很简单:我们想要一个应用,它会为我们随机生成一个超级英雄角色——没什么大不了的,对吧?

这是一个开始,但显然我们需要更多的细节。例如,什么是英雄?它们有什么属性吗?有超能力吗?名字怎么样?所有这些问题的答案都是肯定的。

作为优秀的、英勇的程序员,我们总是想计划好我们创建的任何程序。我们需要知道程序的目的,它将如何运行,以及在我们编码和构建它时有助于我们保持正轨的任何细节。

例如,我们知道在该计划中,我们将需要以下内容:

  • 超级英雄名字(随机生成)

  • 超级英雄姓氏(随机生成)

  • 将超级英雄的名字/姓氏合并成一个字符串的代码

  • 在给定范围内随机生成一组统计数据的代码。

  • 随机发电机

此外,我们需要变量来保存我们所有的统计数据;我们的名、姓和组合名;还有我们的超能力。我们还需要一个数据结构——在本例中是lists——来保存我们名字和超能力的值,我们将从中随机选择名字/能力给我们的英雄。

听起来很复杂?别担心,不会的。我们将一步一步地介绍计划的每一部分,让大家熟悉我们已经介绍过的所有内容。那就是说,让我们穿上斗篷和面具,开始超级英雄发电机 3000 的第一部分!

导入模块

首先,我们的程序将依赖于两个模块——一些预先存在的代码,用于执行一项我们可以用来节省时间和减少人为错误的常见任务。第一个是random,我们已经用过了。提醒你一下,random可以用来随机生成数字。它还允许您从列表中随机选择一个(或多个)值——等等。在我们的程序中,我们将它用于两个目的。

我们导入的第二个模块叫做time,这是我们到目前为止还没有涉及到的。它的主要功能之一是允许我们在程序执行中创建一个“暂停”。您希望延迟一部分代码的执行可能有很多原因。出于我们的目的,我们使用time来制造悬念,让程序看起来像是在计算复杂的东西。

让我们创建一个名为 SuperHeroGenerator3000.py 的新文件,并向其中添加以下代码:

# Importing the random module to use for randomizing numbers and strings later

import random

# Importing the time module to create a delay

import time

创造我们的变量

如前所述,这个程序将依赖于相当多的变量和列表来存储数据。为了保存 STATS(或统计)数据,我们将使用变量来满足我们的存储需求。现在,您应该熟悉它们的用法以及如何定义它们。也就是说,让我们将这段代码添加到我们的SuperHeroGenerator3000.py文件中,就在我们导入timerandom模块的下面:

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

answer = ' '

第一组变量将用于保存统计数据,比如你的角色有多聪明,他们有多强壮,等等。请注意,初始值都设置为0。在应用的后面,我们将使用random来更改这些值。然而,就目前而言,我们必须给他们一个价值,所以0就是这样!

您可能会注意到,我们有一个位于统计组之外的变量,名为 answer。一旦程序运行,它会问用户一个问题继续-我们将使用答案字符串变量来保存用户的回答。现在,我们没有给它赋值;用户的输入将在以后填充它。

定义我们的列表

列表用于保存多条数据。superHeroGenerator3000.py 应用依赖于三个列表:一个将保存可能的超级能力列表——命名的超级能力——而另外两个将保存可能的名字和姓氏列表。

在节目的后面,我们将使用随机从这些列表中选择值,给我们的英雄一个名字和超能力。现在,我们需要创建列表并给它们赋值。

现在,使用我提供的值。然而,在你测试了这个程序几次之后,你可以随意添加你自己古怪的名字组合和超级英雄能力到这些列表中——发挥创造力,玩得开心!

以下是列表的代码——将其添加到变量列表下的文件中:

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

现在我们已经有了数据结构,是时候进入代码的下一部分了。

介绍性文本和接受用户输入

我们代码的下一部分旨在问候用户并接受他们的一些输入。正如我们在第五章中了解到的,我们可以通过使用input()函数接受用户的输入。将以下代码添加到您的文件中,就在您新创建的列表的下面:

# Introductory text

print("Are you ready to create a super hero with the Super Hero Generator 3000?")

# Ask the user a question and prompt them for an answer
# input() 'listens' to what they type on their keyboard
# We then use upper() to change the users answer to all uppercase letters

print("Enter Y/N:")

answer = input()
answer = answer.upper())

为了使生活更容易,在我们接受用户输入后,我们将他们的answer转换成全部大写字母。我们为什么要这样做?以使我们在他们回答时不必检查小写和大写的组合。如果我们没有将文本全部转换为大写,我们将不得不检查“是”、“是”、“是”、“是”等等。转换字符串并检查一个简单的“是”(或者在本例中是“Y”)要容易得多,也更有效。

answer的值不等于为“是”时,我们通过使用重复的while循环来检查用户的答案。一旦条件满足,循环退出,程序继续,乐趣才真正开始!

while循环添加到代码中,就在介绍性文本和input()部分的下面:

# While loop to check for the answer "Y"
# This loop will continue while the value of answer IS NOT "Y"
# Only when the user types "Y" will the loop exit and the program continue

while answer != "Y":
    print("I'm sorry, but you have to choose Y to continue!")
    print("Choose Y/N:")
    answer = input()
    answer = answer.upper())

print("Great, let's get started!")

制造悬念!

就像在真实的写作中,有时在我们的计算机编程中,我们想要戏剧性地添加悬念或暂停,以使用户认为一些真正酷的事情正在发生。或者我们可能希望间歇地暂停一个程序,给用户时间阅读屏幕上的文本,而不是让它滚动得太快。

无论是哪种情况,我们都可以通过使用一个你还没有学会的新模块来实现这种戏剧性的效果:时间()。

虽然我们将在代码中使用 time(),但我们还不会涵盖整个函数——因为现在我们只想使用这个方便的新工具的一个方面,那就是利用它的sleep函数。

像任何其他函数一样,时间接受参数——六个常用参数和一些不常用的参数。睡眠使你的程序暂停,以秒计算,在我们看来是这样的:

时间.睡眠(3)

括号中的数字是您想要暂停的秒数。我们可以键入并完成它,但是——如前所述——我们需要一些戏剧性的天赋!因此,我们不想单独使用 time.sleep(),而是想在用户屏幕上打印一些省略号(…)来模拟等待时间。只是看起来更酷!

为此,我们将把 time()函数放在一个重复三次的 for 循环中。每次通过循环,我们的程序将打印到用户的屏幕上。

将此代码添加到您的。py 文件:

print("Randomizing name...")

# Creating suspense using the time() function

for i in range(3):
    print("...........")
    time.sleep(3)

print("(I bet you can't stand the suspense!)")
print("")

理论上,如果我们在此时运行我们的程序,我们将在屏幕上看到以下输出:

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

time()功能启动时,每个“…………”打印一行正好需要 3 秒钟,创造了我们的“戏剧性停顿”

既然我们已经有了介绍性的文本,了解了如何在程序中暂停或产生停顿,并且已经有了初始变量/列表——以及我们导入的模块——是时候进入应用的核心部分了!

在下一节中,我们将创建代码的一部分,随机生成超级英雄的所有不同部分。为此,我们依赖于黄金旧random()模块。

随机选择超级英雄的名字

每个超级英雄都需要五样东西:

  • 很酷的服装

  • 超级大国

  • 无害的收入来源,使他们永远不会被人看到白天工作

  • 纸巾擦去所有那些孤独的微波晚餐的眼泪(超级英雄没时间约会!)

  • 当然,还有一个很棒的名字

超级发电机 3000 代码的下一步是对名称生成部分进行编程。之前,您可能还记得,我们创建了两个充满超级英雄名字和姓氏的列表。提醒一下,以下是这些列表:

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

我们的名字生成部分代码背后的想法是,我们想从这两个列表中各取一个名字,并将它们合并成一个,创建我们的英雄的名字。有许多方法可以实现这一点,但就我们的目的而言,我们希望随机选择这两个值——这样,每次程序运行时,它都会创建一个唯一的名称组合。

在深入研究之前,让我们先看看实现这种效果的代码。将以下代码添加到您的SuperHeroGenerator3000.py文件中,就在time()代码的下面:

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

print("Your Super Hero Name is:")
print(superName)

这段代码非常容易理解。我们首先创建一个名为superName的变量,它的任务是保存我们英雄的姓和名的组合(从列表superFirstNameSuperLastName中获得)。

接下来,我们使用 random()——特别是 random . choice——从我们的列表superFirstName中随机选择一个值,从superLastName中随机选择一个值。

代码行的这一部分内容如下:

+ " " +

可能看起来令人困惑;然而,它的目的很简单。在这种情况下,+符号被用来连接,或者将我们的两个字符串加在一起。因为我们希望名字和姓氏之间有一个空格,所以我们也必须通过在中间添加" "来添加或者连接一个空格。否则,我们可以只写random.choice(superFirstName) + random.choice(superLastName).

最后,我们通过使用:print(superName)打印出新创建的 superName 的值来完成程序的这一部分。

现在,如果我们运行我们的程序,它会产生类似这样的结果:

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

Your Super Hero Name is:
Improbably Max

或者

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

Your Super Hero Name is:
Stupendous Hero

注意

因为这些值是随机生成的,你的超级英雄的名字可能会与我提供的例子不同。

快速入住

在我们继续下一步之前,让我们检查一下你的代码是否与我的匹配。如果您一直按照正确的顺序编写代码,您的程序应该如下所示。如果没有,不用担心——只需修改您的代码以匹配我的代码,并重新阅读这些部分以找出哪里出错了!

下面是您的代码目前应该呈现的样子:

# Importing the random module to use for randomizing numbers and strings later

import random

# Importing the time module to create a delay

import time

# Creating - or initializing - our variables that will hold character stats

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

answer = ''

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Introductory text

print("Are you ready to create a super hero with the Super Hero Generator 3000?")

# Ask the user a question and prompt them for an answer
# input() 'listens' to what they type on their keyboard
# We then use upper() to change the users answer to all uppercase letters

print("Enter Y/N:")

answer = input()
answer = (answer.upper())

# While loop to check for the answer "Y"
# This loop will continue while the value of answer IS NOT "Y"
# Only when the user types "Y" will the loop exit and the program continue

while answer != "Y":
    print("I'm sorry, but you have to choose Y to continue!")
    print("Choose Y/N:")
    answer = input()
    answer = answer.upper())

print("Great, let's get started!")

print("Randomizing name...")

# Creating suspense using the time() function

for i in range(3):
    print("...........")
    time.sleep(3)

print("(I bet you can't stand the suspense!)")
print("")

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

print("Your Super Hero Name is:")
print(superName)

随机分配超能力

现在有趣的部分来了——随机产生我们英雄的超能力!毕竟,如果他不能在不到一天的时间里从鼻子里射出激光束或者长出一把完整的胡子,他就不会那么超级了,不是吗?

就像我们的superFirstNamesuperLastName列表一样,你会记得我们已经创建了一个拥有超能力的列表,恰当地命名为superPowers。正是从这个列表中,我们将选择我们的超级英雄在他的武器库中拥有什么力量。

注意

在我们完成整个程序并且你已经测试了几次之后,请随意将你自己的超能力组合添加到superPowers列表中——尽情享受,尽可能地发挥创造力!

将以下代码添加到您的superHeroGenerator3000.py文件中,直接放在随机生成您的英雄名字的代码部分的下面:

print("")
print("Now it's time to see what super power you have!)")
print("(generating super hero power...)")

# Creating dramatic effect again

for i in range(2):
    print("...........")
    time.sleep(3)

print("(nah...you wouldn't like THAT one...)")

for i in range(2):
    print("...........")
    time.sleep(3)

print("(almost there....)")

# Randomly choosing a super power from the superPowers list
# and assigning it to the variable power

power = random.choice(superPowers)

# Printing out the variable power and some text
print("Your new power is:")
print(power)
print("")

正如您所看到的,这段代码首先将一些文本打印到用户的屏幕上,通知他们英雄的超能力即将产生。在这之后,我们使用time.sleep()不是一次,而是两次,以创造更戏剧性的效果并减慢程序速度。这一次,通过我们的for循环,我们每次只打印两行.......——每行持续 3 秒钟。

代码的下一部分:

power = random.choice(superPowers)

创建一个名为power的新变量,然后从superPowers列表中给它分配一个随机值。最后,这段代码通过打印出power的值来结束,这样用户就可以看到选择了什么样的超级能力。

从理论上讲,如果我们现在运行这个程序,我们将会得到类似如下的结果:

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

Your Super Hero Name is:
Astonishing Dingo

Now it's time to see what super power you have!)
(generating super hero power...)
...........
...........
(nah...you wouldn't like THAT one...)

...........
...........
(almost there....)
Your new power is:
Flying

或者

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

Your Super Hero Name is:
Astonishing Stallion

Now it's time to see what super power you have!)
(generating super hero power...)
...........
...........
(nah...you wouldn't like THAT one...)
...........
...........
(almost there....)
Your new power is:
Can Eat a Lot of Hot Dogs

请记住,您的结果可能会有所不同,因为超能力和超级英雄的名字是随机生成的。

结束我们的节目

我们几乎完成了创建您的第一个完整的程序!用无与伦比的斯坦·李的话说——精益求精!

我们应用的最后一部分将随机生成我们英雄的统计数据。您可能还记得,在我们代码的开始,我们创建了七个变量(brains, braun, stamina, wisdom, constitution, dexterityspeed),并给每个变量赋值0

在下面的代码中,我们将为这七个变量中的每一个赋予一个从 1 到 20 的随机整数值。我们使用在第二章中讨论过的random.randint()函数来实现。

将以下内容添加到您的superHeroGenerator3000.py文件中:

print("Last but not least, let's generate your stats!")
print("Will you be super smart? Super strong? Super Good Looking?")
print("Time to find out!")

# Creating dramatic effect and slowing the program down again

for i in range(3):
    print("...........")
    time.sleep(3)

# Randomly filling each of the below variables with a new value
# The new values will range from 1-20

brains = random.randint(1,20)
braun = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

# Printing out the statistics

print("Your new stats are:")
print("")
print("Brains: ", brains)
print("Braun: ", braun)
print("Stamina: ", stamina)
print("Wisdom: ", wisdom)
print("Constitution: ", constitution)

print("Dexterity: ", dexterity)
print("Speed: ", speed)
print("")

# Printing out a full summary of the generated super hero
# This includes the hero's name, super power, and stats

print("Here is a summary of your new Super Hero!")
print("Thanks for using the Super Hero Generator 3000!")
print("Tell all your friends!")
print("")
print("Character Summary:")
print("")
print("")
print("Super Hero Name: ", superName)
print("Super Power: ", power)
print("")
print("Brains: ", brains)
print("Braun: ", braun)
print("Stamina: ", stamina)
print("Wisdom: ", wisdom)
print("Constitution: ", constitution)
print("Dexterity: ", dexterity)
print("Speed: ", speed)

如果我们检查新代码的这一部分:

brains = random.randint(1,20)
braun = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

我们可以看到给变量随机赋值是多么容易。括号中的数字代表允许范围的最低值和允许的最高值;该数字将始终介于 1 和 20 之间。

超级发电机 3000 代码-完成!

现在是时候享受我们第一个完整项目的荣耀了!拍拍自己的背,跑去告诉你所有的朋友,我是一个多么伟大的老师,这本书是自奶酪切片以来最好的东西!我在骗谁——大块的奶酪也一样棒!

我们需要做的最后一件事是确保您的代码与本书中的内容完全匹配。一旦我们这样做了,你就可以自由地反复运行这个程序,改变列表的值,并邀请你所有的朋友和老师来生成他们自己的超级英雄!

以下是superHeroGenerator3000.py的完整代码——比较您的代码并确保其匹配:

# Importing the random module to use for randomizing numbers and strings later

import random

# Importing the time module to create a delay

import time

# Creating - or initializing - our variables that will hold character stats

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

answer = ''

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Introductory text

print("Are you ready to create a super hero with the Super Hero Generator 3000?")

# Ask the user a question and prompt them for an answer
# input() 'listens' to what they type on their keyboard
# We then use upper() to change the users answer to all uppercase letters

print("Enter Y/N:")

answer = input()
answer = answer.upper())

# While loop to check for the answer "Y"
# This loop will continue while the value of answer IS NOT "Y"
# Only when the user types "Y" will the loop exit and the program continue

while answer != "Y":
    print("I'm sorry, but you have to choose Y to continue!")
    print("Choose Y/N:")
    answer = input()
    answer = answer.upper())

print("Great, let's get started!")

print("Randomizing name...")

# Creating suspense using the time() function

for i in range(3):
    print("...........")
    time.sleep(3)

print("(I bet you can't stand the suspense!)")
print("")

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists

# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

print("Your Super Hero Name is:")
print(superName)
print("")
print("Now it's time to see what super power you have!)")
print("(generating super hero power...)")

# Creating dramatic effect again

for i in range(2):
    print("...........")
    time.sleep(3)

print("(nah...you wouldn't like THAT one...)")

for i in range(2):
    print("...........")
    time.sleep(3)

print("(almost there....)")

# Randomly choosing a super power from the superPowers list

# and assigning it to the variable power

power = random.choice(superPowers)

# Printing out the variable power and some text
print("Your new power is:")
print(power)
print("")

print("Last but not least, let's generate your stats!")
print("Will you be super smart? Super strong? Super Good Looking?")
print("Time to find out!")

# Creating dramatic effect and slowing the program down again

for i in range(3):
    print("...........")
    time.sleep(3)

# Randomly filling each of the below variables with a new value
# The new values will range from 1-20

brains = random.randint(1,20)
braun = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

# Printing out the statistics

print("Your new stats are:")
print("")
print("Brains: ", brains)
print("Braun: ", braun)
print("Stamina: ", stamina)
print("Wisdom: ", wisdom)
print("Constitution: ", constitution)
print("Dexterity: ", dexterity)
print("Speed: ", speed)
print("")

# Printing out a full summary of the generated super hero
# This includes the hero's name, super power, and stats

print("Here is a summary of your new Super Hero!")
print("Thanks for using the Super Hero Generator 3000!")
print("Tell all your friends!")
print("")
print("Character Summary:")
print("")
print("")
print("Super Hero Name: ", superName)
print("Super Power: ", power)
print("")
print("Brains: ", brains)
print("Braun: ", braun)
print("Stamina: ", stamina)
print("Wisdom: ", wisdom)
print("Constitution: ", constitution)
print("Dexterity: ", dexterity)
print("Speed: ", speed)

当您运行这个程序时,您应该会看到类似于下面的结果,请记住,超级英雄的名字、超能力和属性都是不同的,因为它们都是随机生成的——我知道,我听起来像一张破唱片!

可能的结果:

Are you ready to create a super hero with the Super Hero Generator 3000?
Enter Y/N:
y
Great, let's get started!
Randomizing name...
...........
...........
...........
(I bet you can't stand the suspense!)

Your Super Hero Name is:
Wonder Man

Now it's time to see what super power you have!)
(generating super hero power...)
...........
...........
(nah...you wouldn't like THAT one...)
...........
...........
(almost there....)
Your new power is:
Good At Skipping Rope

Last but not least, let's generate your stats!
Will you be super smart? Super strong? Super Good Looking?
Time to find out!
...........
...........
...........
Your new stats are:

Brains:  8
Braun:  13
Stamina:  5
Wisdom:  15
Constitution:  20
Dexterity:  11
Speed:  9

Here is a summary of your new Super Hero!
Thanks for using the Super Hero Generator 3000!
Tell all your friends!

Character Summary:

Super Hero Name:  Wonder Man

Super Power:  Good At Skipping Rope

Brains:  8
Braun:  13
Stamina:  5
Wisdom:  15
Constitution:  20
Dexterity:  11
Speed:  9

七、利用函数、模块和内置功能节省时间

现在我们已经正式创建了我们的第一个成熟的 Python 应用(如果你想跳过的话,回到第六章)!),是时候开始学习如何真正利用我们的编程能力,尽可能成为最好的程序员了。

到目前为止,在本书中,我们已经提到了尽可能高效地使用代码的重要性。编码不仅有效地增加了我们一天可以完成的工作量,它还有其他几个好处。首先,它有助于确保我们的程序使用尽可能少的内存和处理能力,其次,它有助于减少代码中的错误数量。后者之所以能够实现,自然是因为我们输入的越少,输入错误或出现编程逻辑或语法错误的机会就越少。

高效工作的一部分包括在我们创建新程序时反复重用经过测试和验证的代码片段。这些代码通常是为了执行常见的任务而编写的,可以是几行简单的代码,也可以是几千行。然而,关键的一点是,我们知道它们是可行的,我们可以简单地将它们保存在自己的小文件中,并在需要时将其导入到我们的程序中,而不是一遍又一遍地输入所有的代码,这为我们节省了大量的时间和错误。

以这种方式使用时,这些代码片段被称为模块。简单来说,模块就是包含代码的文件。就这样。

到目前为止,我们已经在本书中使用了几个模块,包括时间和随机。在这一章中,我们不仅要学习如何创建我们自己的模块,还要看看 Python 提供的一些更流行和最常用的模块。毕竟,Python 内置的大量经过实践检验的真正的 Python 模块——以及由大型 Python 社区创建的模块——是 Python 成为如此强大和重要的编程语言的原因之一!

所以,放下那些美味的玉米味薯片,擦掉手指上的奶酪粉(一定不要沾到新的漂亮斗篷上!)并准备进一步扩展您的编程能力,因为我们将深入研究任何超级英雄程序员的终极武器——模块!

定义模块

现在我们知道了模块是什么,您可能会发现自己想知道一个模块到底可以包含什么。从我们之前的定义出发,一个模块可以包含任何代码。它可能有一组函数,可能是一个将一串文本写到用户屏幕上的脚本,可能包含一个变量列表,甚至可能是几行将其他模块导入到程序中的代码。

只要是 Python 文件(。py)并包含代码,它是一个模块。

从技术上讲,Python 中有三种类型的模块。它们是:

  • 内置的

  • 包装

  • 自定义/定制创建

内置的

内置指的是已经是 Python 库的标准部分的模块和函数。当您执行 Python 安装时,这些模块是预安装的。它们包括一些有用的函数,比如datetime(允许您处理日期和时间数据类型)、random(用于随机生成数字)和SocketServer(用于创建网络服务器框架)。

你已经熟悉了一些内置的,因为我们在本书的例子中已经使用了它们。有相当多的内置模块是 Python 的标配。要查看完整的名单,可以访问: https://docs.python.org/3.7/py-modindex.html 。但是,请注意,这个列表会随着每个版本而变化,所以在访问 Python 时,请务必检查您正在使用的 Python 版本。org 网站。

当然,查看内置 Python 模块列表的一个更简单的方法是简单地使用以下代码:

# Print a list of Python Built-in Modules

print(help("modules”))

当您运行这段代码时,Python 会打印出您当前已经安装的所有内置模块的列表,如下所示:

请稍候,我正在收集所有可用模块的列表…

BooleanExamples            _testmultiphase     gettext        reprlib
BooleanLogic               _thread             glob           rlcompleter
ConditionalStatements      _threading_local    grep           rpc
Count10                    _tkinter            gzip           rstrip
DoomsdayClock              _tracemalloc        hashlib        run
Example1                   _warnings           heapq          runpy
InfiniteLoop               _weakref            help           runscript
LearningText               _weakrefset         help_about     sched
ListExample                _winapi             history        scrolledlist
LogicalOperatorsExample    abc                 hmac           search
MathIsHard                 aifc                html           searchbase
MultipleElifs              antigravity         http           searchengine
OrExample                  argparse            hyperparser    secrets
PowersWeaknesses           array               idle           select
RandomGenerator            ast                 idle_test      selectors
...

当然,看到内置列表是很好的,但是更好的是知道它们实际上是做什么的,而不必登录到互联网上用谷歌搜索它们。幸运的是,Python 有两个内置功能可以帮助解决这个问题!

第一个是.__doc__——也称为文档字符串或文档字符串。您遇到的每个模块都应该有一个 docstring 作为其定义的一部分,它基本上服务于该函数或模块的用途的“文档”。要读取模块的文档,我们可以按以下方式调用这个 docstring:

# First we must import the module
import time

# Then we can print out its documentation

print (time.__doc__)

您希望查看其文档的模块名称位于.__doc__命令之前。

如果您将该代码放在一个文件中并运行它,您的结果将如下所示:

This module provides various functions to manipulate time values.

There are two standard representations of time.  One is the number
of seconds since the Epoch, in UTC (a.k.a. GMT).  It may be an integer
or a floating point number (to represent fractions of seconds).
The Epoch is system-defined; on Unix, it is generally January 1st, 1970.
The actual value can be retrieved by calling gmtime(0).

The other representation is a tuple of 9 integers giving local time.
The tuple items are:
  year (including century, e.g. 1998)
  month (1-12)
  day (1-31)
  hours (0-23)
  minutes (0-59)
  seconds (0-59)
  weekday (0-6, Monday is 0)
  Julian day (day in the year, 1-366)
  DST (Daylight Savings Time) flag (-1, 0 or 1)
If the DST flag is 0, the time is given in the regular time zone;
if it is 1, the time is given in the DST time zone;
if it is -1, mktime() should guess based on the date and time.

另一个选项是查看文档——事实上,您可能希望同时使用这两个选项,因为这两个命令的文档可能是不同的。例如,如果您输入以下代码:

# First we must import the module

import time

# Then we can print out its documentation using our second method

help(time)

并运行它,您将得到一个不同的、比您使用.__doc__时更冗长的响应:

Help on built-in module time:

NAME
    time - This module provides various functions to manipulate time values.

DESCRIPTION
    There are two standard representations of time.  One is the number
    of seconds since the Epoch, in UTC (a.k.a. GMT).  It may be an integer
    or a floating point number (to represent fractions of seconds).
    The Epoch is system-defined; on Unix, it is generally January 1st, 1970.
    The actual value can be retrieved by calling gmtime(0).

    The other representation is a tuple of 9 integers giving local time.
    The tuple items are:
      year (including century, e.g. 1998)
      month (1-12)
      day (1-31)
      hours (0-23)
      minutes (0-59)
      seconds (0-59)
      weekday (0-6, Monday is 0)
      Julian day (day in the year, 1-366)
      DST (Daylight Savings Time) flag (-1, 0 or 1)
    If the DST flag is 0, the time is given in the regular time zone;
    if it is 1, the time is given in the DST time zone;
    if it is -1, mktime() should guess based on the date and time.

这个结果实际上只是将要打印的整个文档的一小部分。

要了解区别,请尝试同时使用两者。将这段代码输入到一个名为printDocumentation.py的新 Python 文件中并运行它,检查结果以查看不同之处:

# First we must import the module whose documentation we wish to view

import time

# Printing documentation using .__doc__ or docstring

print (time.__doc__)

# Creating a dividing line so that we can see where the next set of
# Documentation begins.

 print("Here is what using HELP looks like...")
 print("######################################")

# Printing documentation using help()

help(time)

这段代码的结果太大了,无法包含在本书中,但是您可以自己运行这个程序来查看所有的文档。请务必记下哪个文档属于我们用来读取 docstring 的哪个方法。

包装

在导入模块之前,您必须首先安装它——也就是说,如果它没有预打包在您的 Python 安装中。我们可以用来安装一个非标准包(或由社区开发的包)的一种方法是使用一个名为pip的内置功能。pip在 Python 的大多数当前版本中是自动安装的,所以除非您使用的是该语言的遗留版本,否则您应该已经准备好了。

pip是 Python 及更高版本附带的安装程序。要使用该程序,您必须启动您的命令行窗口(您可以通过访问开始,然后运行,然后键入 CMD 来完成)。从那里,您可以通过在命令提示符下键入“pip”来查看可能的pip命令列表。

现在,您只需要理解一个简单的 pip 命令:install。然而在我们使用它之前,我们总是想检查我们是否已经安装了我们想要安装的包。

为此,我们返回到 IDLE 并键入:

import <nameofmodule>

例如,如果我们想查看是否安装了时间模块,我们可以键入:

import time

如果我们收到一个错误,我们知道那个特定的模块还没有安装。

为了解决这个问题,我们回到我们的命令行——或 CMD——并安装模块。对于我们的例子,让我们使用Pygame包,它是一个流行的包,有助于视频游戏开发(我们将在后面的章节中讨论这个主题)。

在命令提示符下,只需输入:

python -m pip install Pygame

几秒钟后,命令行将开始下载和安装软件包的过程。一旦完成,您将看到类似于图 7-1 的消息。

img/468718_1_En_7_Fig1_HTML.jpg

图 7-1

恭喜你!您现在已经安装了您的第一个 Python 包!

创建您自己的模块

使用预先存在的内置模块和包是使程序更高效、更不容易出错的好方法。另一个你可以用来节省时间和键盘敲击的工具是创建你自己的模块,你可以反复使用。

创建我们的模块的第一部分是创建一个我们可以从另一个程序中调用或引用的函数。对于这个练习,我们需要两个 Python 文件。我们将从创建主程序将使用的实际模块开始。

创建一个文件called ourFirstModule.py并输入以下代码:

# Define your function using def

def firstFunction():

      print("This is our first function!")

保存文件并尝试运行它。虽然您可以看到程序确实执行了,但似乎什么也没发生。这是因为我们只定义了我们的函数将要做什么,但是我们还没有调用它,调用它,或者告诉它做任何事情。

为了实际使用这个函数,我们必须从另一个文件中调用它。

创建另一个名为testingModule.py的文件,并输入以下代码:

# We first have to import our module
# We import our module by using the name of the file, minus the .py extension

import ourFirstModule

# Now we call the function to use it

ourFirstModule.firstFunction()

运行该文件时,您应该会看到以下结果:

This is our first function!

祝贺您,您已经创建了您的第一个模块,并成功地从另一个程序中调用了它!

当然,模块中可以有多个函数,所以让我们再添加几个函数,并在我们的文件中练习调用它们。打开备份您的ourFirstModule.py文件并编辑代码,如下所示:

# Define your function

def firstFunction():

      print("This is our first function!")

# Define a second function

def secondFunction():
    print("Look, a second function!")

# Define a variable

a = 2+3

接下来,我们需要编辑我们的testingModule.py文件,以利用我们新定义的函数和变量。修改代码,使其如下所示:

# We first have to import our module
# We import our module by using the name of the file, minus the .py extension

import ourFirstModule

# Now we call the function to use it

ourFirstModule.firstFunction()

# Calling our second function

ourFirstModule.secondFunction()

# Calling and printing a variable within our module

print("The value of a is: ",ourFirstModule.a)

除了调用不是一个而是两个函数之外,这段代码还打印出了名为a的变量的值。我们使用代码print(ourFirstModule.a)来实现这一点。部分ourFirstModule引用ourFirstModule.py文件并告诉 Python 从哪里提取函数,而.a告诉它打印什么变量。例如,如果我们的变量被命名为lastName,它应该是这样的:print(ourFirstModule.lastName)

最后,对于我们创建的任何代码,我们总是希望确保记录我们的工作。之前,我们使用了.__doc__help()来打印模块的文档。现在,我们将使用多行注释(或三组)来创建我们自己的文档。

打开您的ourFirstModule.py文件,修改第一个函数firstFunction()的代码,添加以下注释:

# Define your function

def firstFunction():

    """ This is the documentation - or docstring - for firstFunction()
We can put examples of use here or just document what the function is for
That way future programmers - or ourselves later on - can read the
"helpfile" for our firstFunction and know what it was intended for
    """

print("This is our first function!")

第一组缩进的"""和第二组缩进的"""之间的所有内容都被认为是注释或文档,如前一章所讨论的。

现在,打开您的testingModule.py文件,让我们向其中添加以下代码,以便打印出文档:

# print the helpfile for firstFunction()
help(ourFirstModule)

您可以将这段代码放在文件中的任何地方,但是我选择将它直接放在打印 firstFunction 的 print()函数下面。

运行该程序,您应该会看到以下结果:

This is our first function!
Help on module ourFirstModule:

NAME
    ourFirstModule - # Define your function

FUNCTIONS
    firstFunction()
        This is the documentation - or docstring - for firstFunction()
        We can put examples of use here or just document what the function is for
        That way future programmers - or ourselves later on - can read the
        "helpfile" for our firstFunction and know what it was intended for

    secondFunction()

DATA
    a = 5

Look, a second function!
The value of a is: 5

常见内置功能

Python 有很多很棒的内置功能,到目前为止,我们已经在本书中讨论了很多。但是就像一个可靠的多用途皮带中的物品一样,你手头永远不会有太多的工具。当然,一罐防鲨剂可能看起来很可笑,但是等你和那个能屏住呼吸,哦,是的,还能和鲨鱼说话的人打一场仗。你觉得防鲨剂有多傻?

内置功能近 70 个,大部分你作为程序员在生活中都会用到。现在,我们将讨论一些到目前为止我们已经跳过的更常见的问题。我们将按类别处理它们,从字符串函数开始。

字符串函数

正如您可能猜到的,字符串函数是处理字符串的函数。我们已经介绍了一些,包括str.upper()str.lower(),它们分别将字符串转换成大写和小写。

此外,实际上使一个字符串大写或小写,你也可以执行检查,看看字符串的内容实际上是什么情况。例如,您可能想知道用户是否输入了全部大写字母。要进行检查,您可以使用以下代码:

# Create a string of all uppercase letters

testString = "I AM YELLING!"

print("Is the user yelling?")

# Check to see if the value of testString consists of all uppercase letters

print(testString.isupper())

在这种情况下,我们使用名为 str.isupper()的字符串函数来检查字符串是否包含大写字母。如果您要运行这段代码,您将得到一个布尔响应(真或假):

Is the user yelling?
True

请注意,如果字符串中的任何字符是小写的,它将返回一个False值,因为该函数正在检查整个字符串是否包含大写字母。

如果我们想检查一下是否是小写,我们可以使用字符串函数 str.islower(),如下所示:

# Create a string of all uppercase letters

testString = "I AM YELLING!"

print("Is the user yelling?")

# Check to see if the value of testString consists of all uppercase letters

print(testString.islower())

当然,在本例中,它将返回一个False

有时候我们可能想要检查用户输入的是什么类型的字符。例如,如果用户在填写表单,我们想知道他们的名字和姓氏,我们不希望他们输入数值——除非他们是机器人或外星人,请注意。

要检查一个字符串是否只包含字母(没有数字),您可以使用str.isalpha():

# Create a string to check if the variable only contains letters

firstName = "James8"

# Check to see if the value of firstName contains any numbers

print("Does your name contain any letters?")

if firstName.isalpha() == False:
    print("What are you, a robot?")

由于字符串firstName的值不仅仅包含字母(它包含一个数字),那么if返回一个False值,导致print()函数打印出它的文本:

Does your name contain any numbers?
What are you, a robot?

如果firstName 中只有包含字母字符(A-Z 和 A-Z),那么if将返回True,并且不会打印任何内容。

我们还可以检查这些值是只有数字还是只包含数字。例如,我们可能希望确保某人没有在社会保险或电话号码字段中输入字母。为了检查字符串中只有数字的值,我们使用函数str.isnumeric():

# Create a string to check if the variable only contains numbers

userIQ = "2000"

# Check to see if the value if userIQ contains only numbers and no letters

if userIQ.isnumeric() == False:
    print("Numbers only please!")
else:
    print("Congrats, you know the difference between a number and a letter!")

同样,我们检查userIQ是否只包含数字的评估结果是True还是False。由于userIQ只包含数字——没有字母——结果为真,我们得到结果:

Congrats, you know the difference between a number and a letter!

我们还可以检查我们的字符串是否只包含空格——也称为空白。为此,我们使用函数str.isspace():

# Check to see if the value of UserIQ contains all spaces or whitespace characters

if userIQ.isspace() == True:
    print("Please enter a value other than a bunch of spaces you boob!")

由于userIQ不包含所有空格,所以什么都不会发生。如果只有空格,Python 就会执行我们定义的 print()函数。

我们可以使用的另一个有用的字符串函数是len(),它让我们计算一个字符串中的字符数。你可能会问自己,“我到底为什么要这么做?”答案很简单:您可能希望限制变量中的字符数,比如密码,或者确保它有足够的字符。

又或许,你和我一样有强迫症(强迫症),觉得什么都要数。我认为这是我很多很多超能力中的一个…

要计算字符串中的字符数,您可以使用类似如下的代码:

# Create a variable to count the number of characters it holds using len()

testPassword = "MyPasswordIsPassword!"

当您运行此代码时,您将得到以下结果:

21

数字函数

现在我们已经学习了一些新的字符串函数,让我们继续处理数字。我们之前检查了几个帮助我们处理数字的函数,以及让我们执行漂亮的数学方程而不伤害我们大脑(无论如何,太多)的运算符。

让我们的大脑更擅长数字(不要告诉你的英语老师这是我写的!),让我们看看更多的函数,它们将提升我们的编程技能,并使我们看起来像众所周知的火箭科学家。

有时当我们和数字打交道时,我们会被要求告诉我们的老板哪个数字比所有其他数字都高。为了找出一系列数字中的最大值,我们使用max()

# Create a list containing a group of numbers

studentGrades = [100, 90, 80, 70, 60, 50, 0]

# Use max() to find the highest number in the studentGrades list

print("What is the highest grade in the studentGrades list?")
print:("Answer :")
print(max(studentGrades))

如果我们运行这段代码,将会导致:

What is the highest grade in the studentGrades list?
100

因为100是我们列表中 studentGrades 的最高值。如果我们想找出一系列数字的最小值,我们可以使用 min():

# Create a list containing a group of numbers

studentGrades = [100, 90, 80, 70, 60, 50, 0]

# Use max() to find the highest number in the studentGrades list

print("What is the highest grade in the studentGrades list?")
print:("Answer :")
print(max(studentGrades))

# Use min() to find the lowest number in the studentGrades list

print("What is the lowest grade in the studentGrades list?")
print:("Answer :")
print(min(studentGrades))

运行后,该代码输出:

What is the highest grade in the studentGrades list?
100
What is the lowest grade in the studentGrades list?
0

我们也可以使用min()max()而不创建列表。要单独使用它们,您应该键入:

print(min(100, 90, 80, 70, 60, 50, 0))

print(max(100, 90, 80, 70, 60, 50, 0))

注意

您还可以在字符串上使用 min()和 max(),例如,在从 a 到 z 排列的字母表上使用 min 将返回“a”,而使用 max()将返回“z”。

另一种常见的做法是对给定列表中的所有数字求和。也许你需要计算你公司的工资总额或工作时间。为此,您可以使用sum()函数。让我们用下面的代码来总结一下:

# Create another list containing more numbers, representing payroll

totalPayroll = [500, 600, 200, 400, 1000]

# Use sum() to calculate the sum of the numbers in a list

print("How much did we pay employees this week?")
print("The total payroll was: ")
print(sum(totalPayroll))

此示例的输出将是:

How much did we pay employees this week?
The total payroll was:
2700

练习你的新函数

我们在你的超级英雄编程实用带上增加了很多新函数。现在是时候实践你所学的知识来提高你的技能了。在下文中,你会发现一个我们学过的新的字符串函数列表和一个我们在这一章中摆弄过的新的数字/数学函数列表。

您可以随意输入这些代码,并找出新的令人兴奋的方法来使用这些简单而强大的函数。

字符串函数示例

# Create a string of all uppercase

letters

testString = "I am YELLING!"

# Create a string to check if the variable only contains letters

firstName = "James8"

# Create a string to check if the variable only contains numbers

userIQ = "2000"

# Create a variable to count the number of characters it holds using len()

testPassword = "MyPasswordIsPassword!"

# A series of functions are tested below

print("Is the user yelling?")

# Check to see if the value of testString consists of all uppercase letters

print(testString.isupper())

# Check to see if the value of firstName contains any numbers

print("Does your name contain any numbers?")

if firstName.isalpha() == False:
    print("What are you, a robot?")

# Check to see if the value if userIQ contains only numbers and no letters

if userIQ.isnumeric() == False:
    print("Numbers only please!")
else:
    print("Congrats, you know the difference between a number and a letter!")

# Check to see if the value of UserIQ contains all spaces or whitespace characters

if userIQ.isspace() == True:
    print("Please enter a value other than a bunch of spaces you boob!")

# Count the number of characters in a password

print("Let's see how many characters are in testPassword!") 

print("I count: ")

print(len(testPassword))

数字函数示例

# Create a list containing a group of numbers

studentGrades = [100, 90, 80, 70, 60, 50, 0]

# Create another list containing more numbers, representing payroll

totalPayroll = [500, 600, 200, 400, 1000]

# Use max() to find the highest number in the studentGrades list

print("What is the highest grade in the studentGrades list?")
print:("Answer :")
print(max(studentGrades))

# Use min() to find the lowest number in the studentGrades list

print("What is the lowest grade in the studentGrades list?")
print:("Answer :")
print(min(studentGrades))

# Use min() and max() without defining a list

print(min(100, 90, 80, 70, 60, 50, 0))

print(max(100, 90, 80, 70, 60, 50, 0))

# Use sum() to calculate the sum of the numbers in a list

print("How much did we pay employees this week?") 

print("The total payroll was: ")
print(sum(totalPayroll))

在这一集里!

这一集太壮观了!太神奇了!太惊人了!这是蜘蛛…好吧,让我们只是说这是不可思议的,就这样吧(嘿,那些大的漫画公司不拥有这些话!).

在这一章中,你真的在你的编程能力上向前迈进了一大步,学习了如何创建你自己的模块和函数。通过学习更多的内置功能,您甚至能够使用 Python 最强大的组件之一——社区创建的包。

我们讨论了很多,所以,一如既往,这里是我们在这一章中添加到你的超能力工具包中的一些好东西的总结!

  • 有三种类型的模块:内置模块、软件包模块和自定义模块。

  • Python 中预装了内置包,包是由第三方供应商/Python 社区创建的,自定义包是您自己创建的包。

  • 帮助()和。doc help 打印模块的文档或帮助文件:

    示例:帮助(时间)和打印(时间。doc)

  • 帮助(“模块”)列出了您的 Python 安装当前必须提供的所有可用模块。

  • import 将模块导入到程序中。

    示例:导入时间

  • 您可以在命令行上使用 pip 安装软件包:

    python -m pip 安装

  • def 用于定义一个函数。

    Example:

    def firstFunction():
               print("Hello!")
    
    
  • str.upper()和 str.lower()分别将字符串转换为大写和小写。

  • str.isalpha、str.isnumeric 和 str.isspace()都检查是否使用了正确的数据类型。

  • len()计算字符串中的字符数。

  • min()和 max()在数字或字符串值列表中查找最小值和最大值。

  • sum()计算列表中包含的值的总和。

八、使用类和对象

到目前为止,我们已经介绍了一些非常标准的编程语言特性和实践。本章将延续这一传统;然而,这个主题乍一看可能有点难以把握。不过不要担心——你已经走到了这一步,我们已经看到你从一个磕磕绊绊的跟班变成了一个十足的野兽英雄。

如果你的父母在来自蛇发女怪星球的软泥人的攻击中幸存下来,他们会感到骄傲的,或者他们会的。继续前进…

本章将重点介绍一个被称为OOP面向对象编程的概念。你将会学到被称为classesobjectsconstructorssuperclassessubclasses的东西,以及一个被称为inheritance的强大工具。然后,我们将使用这些新的、强大的概念和方法来制作我们在第六章中创建的程序版本。

没错——就在你认为我们无法改进老的超级英雄发电机 3000 时,你的发电机真的让你大吃一惊!我希望你戴着头盔,因为我不会清理那些大脑!

OOP 是什么?

说实话,Python 实际上是一种面向对象的编程语言。不是每个人都这样使用它,也不是每个人都是 OOP 的粉丝——或者真正理解它的真正力量。有些人会认为用面向对象的方式编写会让 Python 变得不那么 Python 化;也就是说,他们认为使用处于面向对象编程核心的方法、类和对象会降低 Python 的可读性和用户友好性。

这种说法可能有些道理,但总的来说,程序员在可读性方面损失的东西,可以在效率、减少错误和良好的编程习惯方面得到弥补。此外,如果你遵循良好的代码文档的实践(正如我们一再讨论的那样),你的代码将非常具有可读性,因为你将在程序的每一部分清楚地陈述你的意图。

面向对象编程(OOP)就是创建可重用的代码。还记得我们如何讨论函数和模块的好处吗?这些规则同样适用于使用 OOP 实践。它对于更复杂或更长的程序来说是完美的,因为它允许您重用代码片段,并将所有内容保存在一个漂亮、紧凑、易于访问的包中。

到目前为止,我们主要依赖于被称为过程化编程的东西。过程代码本质上是按顺序出现的代码行,也是最常用的代码行。在这一章中,我们将改变这一切!

OOP 编程的核心概念——顺便提一下,这个概念也存在于许多其他编程语言中——涉及到被称为对象的东西。

什么是班级(我会被评分吗?)

别担心——我知道“阶级”这个词让你害怕,让你想起关于数学乐趣的长篇大论,或者讲述早期伊特鲁里亚人经济体系的有趣故事。在 Python 中,类要有趣得多;然而,尽管如此,事实上,在一张好的圆周率图中可以找到很多快乐。

蟋蟀

但是我跑题了。

一个类最好被描述为一个对象的 DNA 更好的是,您可以将它视为一个对象的蓝图,甚至是一个模板。这样想一个类:如果你要制造一辆汽车,你不会只是随意地把一些金属和橡胶轮胎钉在一起,然后抱最好的希望。如果你这样做了,你的车就不会跑得太远,也不会看起来那么棒!

相反,你应该创建一个蓝图——或者一个类——包含你希望你的汽车拥有的某些细节或者特性。此外——因为我们英雄程序员都是关于效率的——我们想要创建一个蓝图(类),当我们建造任何汽车时都可以使用。这样,当我们去制造另一种型号的汽车时,我们就不必重新制定计划了。

例如,如果我们为一辆汽车创建一个类,我们可能想说每辆汽车都有四个轮胎、一个挡风玻璃、门、一个引擎等等。这些都是每辆车都会有的普通东西。颜色、油漆、车门数量、轮胎尺寸等等可能不同,但是这些基本特征在每辆车上都会存在。

总而言之,类基本上是一个蓝图,它让我们创建多个具有相同基本特征的对象。每次我们创建一个新对象时,不必编码或定义这些特性,我们只需调用我们的类和 blammo 的一个实例,所有的工作都已经完成了。

如果这个概念还没有完全进入你的大脑,不要担心——当我们开始在实际代码中使用它时,它会变得非常清晰。现在,只需了解基本概念:

班级。都是。蓝图。

什么是对象

如果类是蓝图,那么对象就是我们从它们中创建的对象!用编程术语来说,当我们创建一个对象时,我们正在创建该类的一个实例

对象可以用来表示程序中的一系列事物。如上所述,例如,您可以使用它们来创建车辆。或者他们可以代表一个狗品种或一种类型的雇员。

当然,这是一本超级英雄编程书籍,那么还有什么比创建我们自己的超级英雄(对象)蓝图(类)更好的方式来介绍类和对象的概念——以及如何使用它们呢?

创建我们的第一个班级

创建一个类是一件相对简单的事情。事实上,这非常类似于创建一个函数。当我们创建一个类时——就像函数一样——它被称为定义一个类的。我们使用关键字class来实现:

*```py
class Superhero():

...(write some code)
....(more code here)


这个例子展示了如何创建一个名为超级英雄的类。注意类的命名约定是首字母大写。如果名字中有两个或更多的单词,你应该大写每个单词的第一个字母。例如,如果您想创建一个类来表示一个“美国超级英雄”,您可以使用:

```py
class AmericanSuperHero():
      ...(write some code)
      ...(write some more code)

当然,这些类在技术上不做任何事情。为了使它们有用并执行它们的功能,我们需要向它们添加代码,告诉它们做什么,或者帮助定义我们将从它们创建的对象。

当我们给一个类添加一个函数时,这个函数被称为method。方法必须缩进到它们所属的类之下。

class Superhero():
      def fly(self):
             print("Look at me, I'm so fly!")

这段代码用一个名为fly的方法创建了一个名为Superhero的类,它打印出文本“看看我,我飞得真快!”

当我们定义一个方法时,我们使用def,后跟方法名。方法包含封装在圆括号中的参数。类的每个方法必须至少包含self参数;它们也可以包含任意数量的其他参数(很快会有更多相关内容!).

self用来引用你创建的对象的实例。同样,这将更有意义,因为我们实际上创建了我们的类并让它们工作。

还要注意,方法定义下的代码也必须相对于它所属的方法缩进。

我们可以在一个类中放置任意数量的方法,也可以向它们添加各种代码,包括变量等等。

例如,如果我们想给我们的Superhero类添加两个方法——一个让他飞,另一个让他吃很多热狗——我们可以这样定义我们的类:

class Superhero():
      def fly(self):
             print("Look at me, I'm so fly!")

      def hotDog(self):
             print("I sure do like hot dogs!")

如果我们运行这段代码,什么也不会发生,因为我们所做的只是定义我们的Superhero类。为了实际使用这个类,我们必须创建这个类的一个实例或者一个对象。

创建我们的第一个对象

现在我们有了一个通过我们的Superhero类创建的超级英雄的基本蓝图,我们可以创建我们的第一个英雄,或者更恰当地说,我们的第一个英雄对象。

为了创建一个对象(或一个类的实例),我们必须初始化或创建一个类的副本,类似于创建一个变量并赋予它一个值:

HotDogMan = Superhero()

创建一个对象就是这么简单。现在,对象HotDogMan具有我们的Superhero类的所有特征。Superhero类的实例/对象存储在HotDogMan中,包括我们在创建该类时定义的所有属性和方法。

为了看到这一点,我们可以调用我们在超级英雄类中定义的两个方法,这两个方法现在是 HotDogMan 对象的一部分。调用意味着执行或运行部分代码:

HotDogMan.fly()
HotDogMan.hotDog()

这段代码的第一行告诉 Python 访问HotDogMan对象并寻找一个名为fly的方法,一旦找到,就执行它。第二行做同样的事情,只是它寻找方法hotDog并运行那部分代码。

为了更好地理解我们到目前为止所涉及的一切,让我们创建一个名为SampleClassandObject.py的新文件,并向其中添加以下代码(注意:该代码是我们到目前为止在本章中讨论过的代码,收集到一个文件中):

class Superhero():
      def fly(self):
             print("Look at me, I'm so fly!")

      def hotDog(self):
             print("I sure do like hot dogs!")

HotDogMan = Superhero()
HotDogMan.fly()
HotDogMan.hotDog()

当我们运行这段代码时,我们会得到以下结果:

Look at me, I'm so fly!
I sure do like hot dogs!

这一切都很好,但是,在现实中,这些例子并没有显示类和对象——以及面向对象的能力——所具有的真正能力。现在我们已经理解了类和对象的基本概念,让我们以一种更加实际和真实的方式来使用它们。

改进超级英雄生成器 3000!

如果你还记得第六章的话,我们创建了一个随机生成超级英雄的程序。具体来说,我们随机生成了一个超级英雄名,一个威能,和一些统计数据。为此,我们让用户运行程序,并在显示结果之前回答几个简单的问题。

我们按照非常连续的顺序创建了那个程序;也就是说,我们编写的代码被 Python 解释器——以及任何查看它的程序员——逐行读取。当程序运行时(我想补充的是,完美无缺!),如果我们要创造第二个,或者第一千个超级英雄,会发生什么?要做到这一点,在程序的当前状态下,用户必须一遍又一遍地运行程序。

效率不是很高。

如果用户请求多个英雄,我们可以一直创建一个循环来继续超级英雄的选择过程,或者我们可以继续添加更多的代码来允许更多的超级英雄,但是,我们希望创建尽可能少的代码行,以使我们的程序运行得更好,并减少出错的可能性。

请这样想:我们旧的超级英雄生成器 3000 程序是一个手工构建每个超级英雄的系统。如果我们使用类和对象,我们将拥有一个高科技工厂,可以打印出成千上万的超级英雄,而不必担心人为错误。此外,这将节省大量时间,因为我们不必写这么多代码。

记住所有这些,让我们尝试重新创建超级英雄生成器 3000,这一次利用类和对象。

如果你还记得的话,在我们最初版本的程序中,每个英雄都有一组定义他们身体和精神特征的统计数据。其中包括:

  • 大脑:主人公有多聪明

  • 布劳恩:英雄有多强

  • 耐力:英雄有多少能量

  • 智慧:他们有多聪明,有多少现实生活经验

  • 体质:他们的身体从伤害中恢复和抵抗疾病的能力

  • 灵巧:我们的英雄是多么的杂技和敏捷

  • 速度:英雄有多快

我们可以将这些属性分配给一个Superhero类,这样,当我们从该类创建一个对象时,我们创建的所有英雄都将拥有相同的统计数据。我们这样做是因为我们知道每个英雄都应该至少有一些头脑、头脑、敏捷等等——这些都是标准英雄的共同特征,因此,将成为我们英雄蓝图或模板的一部分。

让我们创建一个名为SuperHeroClass.py的新文件,并向其中添加以下代码:

# Import the random module so we can randomly generate numbers
import random

# Create a Superhero class

that will act as a template for any heroes we create
class Superhero():
    # Initializing our class and setting its attributes
    def __init__(self):
        self.superName = " "
        self.power = " "
        self.braun = braun
        self.brains = brains
        self.stamina = stamina
        self.wisdom = wisdom
        self.constitution = constitution
        self.dexterity = dexterity
        self.speed = speed

# Adding random values to each stat using the random() module
braun = random.randint(1,20)
brains = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

在这段代码中,我们介绍了一种新方法,称为constructor方法。我们用它来初始化任何属于这个类的新数据。constructor方法也被称为__init__方法,当我们需要预先向任何变量添加数据时,它总是我们在类中创建的第一个方法。

我们将参数放在__init__方法的括号中,然后将每个self引用设置为等于每个参数。例如:

self.brains = brains

self.brains设置为等于brains。这样,以后在程序中创建我们的对象时,我们可以引用不同的参数——在本例中,这些参数代表我们的英雄统计数据——并在程序中使用它们。

接下来,在这种情况下,我们希望创建英雄模板,我们希望每个英雄统计数据是随机的,所以我们对每个代表英雄统计数据的参数使用 random()模块。例如:

braun = random.randint(1,20)

braun加一个随机值,范围从 1 到 20。

同样,对于初学者来说,类、对象和方法可能是一个很难掌握的主题,所以要有耐心,并确保遵循代码,即使事情没有马上 100%有意义;有时,您需要看到代码的运行,才能完全理解它的意图。

现在,我们已经建立了我们的初始超级英雄类,并决定了我们创建的任何超级英雄的模板将是什么样子,让我们继续尝试创建该类的一个实例(也称为创建一个对象)。然后,我们将打印出我们英雄的数据。将以下代码添加到 SuperheroClass.py 文件中:

# Import the random module so we can randomly generate numbers
import random
# Create a Superhero class that will act as a template for any heroes we create
class Superhero():
    # Initializing our class and setting its attributes
    def __init__(self):
        self.superName = superName
        self.power = power
        self.braun = braun
        self.brains = brains
        self.stamina = stamina
        self.wisdom = wisdom
        self.constitution = constitution
        self.dexterity = dexterity
        self.speed = speed

# Adding random values to each stat using the random() function
braun = random.randint(1,20)
brains = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

print("Please enter your super hero name: ")

# Creating the Superhero object
hero = Superhero()

# Assigning a value to superName using the user's input

hero.superName = input('>')

# We print out the result of the created object, including its parameters
print("Your name is %s." % (hero.superName))
print("Your new stats are:")
print("")
print("Brains: ", hero.brains)
print("Braun: ", hero.braun)
print("Stamina: ", hero.stamina)
print("Wisdom: ", hero.wisdom)
print("Constitution: ", hero.constitution)
print("Dexterity: ", hero.dexterity)
print("Speed ", hero.speed)
print("")

在这个版本的程序中,我们要求用户为超级英雄输入他们自己的名字,而不是像我们在最初的超级英雄生成器 3000 程序中那样随机生成一个名字。不要担心——我们很快就会随机化这个值。现在,我们想保持事情简单,因为我们让用户输入他们自己的名字,使用input()函数。input()函数的值放在英雄对象的superName参数中。这一切都在生产线上实现:

hero.superName = input('>')

你可能已经注意到我们在这里使用的input()和以前有一点不同。括号中的'>'只是在用户的屏幕上放置一个>提示,这样他们就知道在哪里输入。

接下来,我们打印出了hero对象的每个参数的随机生成值,例如,如下所示:

print("Brains: ", hero.brains)

然后该行的, hero.brains部分告诉 Python 打印存储在hero对象brains参数中的值——类似于变量的工作方式。

如果您运行该程序,您将得到如下结果——请记住,您的值会有所不同,因为它们是随机生成的:

Please enter your super hero name:
>SuperPowerAwesomeManofAction
Your name is SuperPowerAwesomeManofAction.
Your new stats are:

Brains:  10
Braun:  10
Stamina:  5
Wisdom:  17
Constitution:  1
Dexterity:  19
Speed  15

完美到目前为止!现在,让我们添加代码来随机生成英雄的名字和超能力。对于这一部分,我们将添加以下行:

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Randomly choosing a super power from the superPowers list
# and assigning it to the variable power

power = random.choice(superPowers)

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

就在我们定义超级英雄属性的地方。由于我们现在随机生成超级英雄的名字,我们不再需要用户输入,所以我们删除了这些行:

print("Please enter your super hero name: ")

# Assigning a value to superName using the user's input
hero.superName = input('>')

我们不再需要这些,因为我们现在从superFirstNamesuperLastName列表中随机生成superName,就像我们在程序的原始版本中所做的一样。

所以现在,所有这些加在一起,你的代码应该如下所示:如果没有,请再次查看这一部分,并更改您的代码以匹配我的代码:

# Import the random module so we can randomly generate numbers
import random

# Create a Superhero class that will act as a template for any heroes we create
class Superhero():
    # Initializing our class and setting its attributes
    def __init__(self):
        self.superName = superName
        self.power = power
        self.braun = braun
        self.brains = brains
        self.stamina = stamina
        self.wisdom = wisdom
        self.constitution = constitution
        self.dexterity = dexterity
        self.speed = speed

# Adding random values to each stat using the random() function
braun = random.randint(1,20)
brains = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Randomly choosing a super power from the superPowers list
# and assigning it to the variable power

power = random.choice(superPowers)

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

print("Please enter your super hero name: ")

# Creating the Superhero object
hero = Superhero()

# Assigning a value to superName using the user's input
# hero.superName = input('>')

# We print out the result of the created object, including its parameters
print("Your name is %s." % (hero.superName))
print("Your super power is: ", power)
print("Your new stats are:")
print("")
print("Brains: ", hero.brains)
print("Braun: ", hero.braun)
print("Stamina: ", hero.stamina)
print("Wisdom: ", hero.wisdom)
print("Constitution: ", hero.constitution)
print("Dexterity: ", hero.dexterity)
print("Speed ", hero.speed)
print("")

如果您现在运行这个程序,您将得到以下结果(同样,您的值将会不同,因为它们是随机生成的):

Please enter your super hero name:
Your name is Incredible Dream.
Your super power is:  Good At Skipping Rope
Your new stats are:

Brains:  1
Braun:  1
Stamina:  5
Wisdom:  11
Constitution:  6
Dexterity:  9
Speed  13

所以现在,在这一点上,我们的程序几乎与超级英雄生成器 3000 的原始版本一样,只是代码行更少,发生错误的机会更少。一些提示也是不同的——例如,我们还没有询问用户是否想要创建一个英雄,我们还没有在生成值时插入戏剧性的暂停效果。然而,基本框架已经到位,在下一节中,我们将添加一些旧的功能,以及一些新的、非常酷的功能,展示类和对象的真正威力!

继承,子类,等等!

类的一个伟大之处在于,你可以用它们来创建其他的类,并且通过一个叫做inheritance的东西,将它们的属性传递给新创建的类,而不必使用一堆冗长的代码。这类似于你的父母把他们的遗传密码传给你,只是在 Python 中,我们可以说一个类到底继承了什么。

当我们基于另一个类创建一个类时,我们称这个新创建的类为subclass。默认情况下,这些子类继承了创建它们的类的方法和参数——顺便说一下,这些方法和参数被称为父类或超类。

与所有代码一样,有时最好通过一个实际的程序来演示这个想法是如何工作的。

到目前为止,超级英雄生成器 3000 只让我们创建常规的旧超级英雄。然而,正如你所知,并不是所有的英雄都是平等的。例如,从技术上来说,超人只是一个来自另一个星球的外星人,他可以看穿衣服,吃阳光(像一棵黄色植物)来变得强壮。与此同时,蝙蝠侠完全没有超能力;或者更确切地说,他的超能力包括拥有一船的钱,一辆很棒的车,和一个拥有一些牵强的计算机编程技能的管家。我是说,真的吗?我的父母不会发短信,而阿尔弗雷德正在使用世界上最强大的超级电脑。

但是我跑题了。

为了让我们的程序更加真实,我们将为超级英雄引入一个新的属性:超级英雄类型。对于我们创造的每一种类型,我们将给予他们某种形式的奖金。现在,让我们专注于创建两个子类来表示我们新的英雄“类型”。一个是机器人超级英雄,另一个是变异的超级英雄。

下面是它在代码中的样子:

# Creating a subclass of Superhero named Mutate
# Mutate heroes will get a +10 bonus to their speed score.

class Mutate(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a Mutate!")
      self.speed = self.speed + 10

# Creating a subclass of Superhero named Robot
# Robot heroes will get a + 10 bonus to their braun score.

class Robot(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a robot!")
      self.braun = self.braun + 10

这里,我们创建了两个新类,它们实际上都是我们的Superhero类的子类。我们实现这一点的方法是将父类的名称放在新创建的类的括号中。例如:class Mutate(Superhero)告诉 Python 解释器创建一个类,这个类是 Superhero 的子类或子类,并继承它的方法和参数。

然后,我们使用def __init__(self)初始化我们的新子类,并使用Superhero.__init__(self)重新初始化我们的Superhero类,因为从技术上讲,我们将基于类和子类创建新对象。

最后,我们想给我们的英雄一个基于英雄类型的奖励。变异字符将获得速度加成,如这行代码所示:

self.speed = self.speed + 10

而机器人将通过这行代码获得对布劳恩的奖励:

self.braun = self.braun + 10

所有其他英雄属性将保持不变,因为它们最初是在超级英雄职业中产生的;如果我们想再次修改它们的值,我们必须在新创建的子类中显式地这样做。

现在我们已经创建了两个新类,我们需要实际创建一个基于它们的实例/对象来查看它们的运行情况。基于子类创建对象的代码与基于任何类创建对象的代码是一样的;如果我们想创建一个新的变异英雄和一个新的机器人英雄,我们可以使用以下代码行:

hero2 = Robot()

hero3 = Mutate()

让我们创建一些代码来打印普通超级英雄、机器人和变异人的统计数据:

# Creating the Superhero object
hero = Superhero()

# We print out the result of the created object, including its parameters
print("Your name is %s." % (hero.superName))
print("Your super power is: ", hero.power)
print("Your new stats are:")
print("")
print("Brains: ", hero.brains)
print("Braun: ", hero.braun)
print("Stamina: ", hero.stamina)
print("Wisdom: ", hero.wisdom)
print("Constitution: ", hero.constitution)
print("Dexterity: ", hero.dexterity)
print("Speed ", hero.speed)
print("")

# Creating a Mutate object

hero2 = Mutate()
print("Your name is %s." % (hero2.superName))
print("Your super power is: ", hero2.power)
print("Your new stats are:")
print("")
print("Brains: ", hero2.brains)
print("Braun: ", hero2.braun)
print("Stamina: ", hero2.stamina)
print("Wisdom: ", hero2.wisdom)
print("Constitution: ", hero2.constitution)
print("Dexterity: ", hero2.dexterity)
print("Speed ", hero2.speed)
print("")

# Create a Robot character

hero3 = Robot()
print("Your name is %s." % (hero3.superName))
print("Your super power is: ", hero3.power)
print("Your new stats are:")
print("")
print("Brains: ", hero3.brains)
print("Braun: ", hero3.braun)
print("Stamina: ", hero3.stamina)
print("Wisdom: ", hero3.wisdom)
print("Constitution: ", hero3.constitution)
print("Dexterity: ", hero3.dexterity)
print("Speed ", hero3.speed)
print("")

如果您将所有这些新代码添加到您的文件中(我们一会儿就会这样做)并运行它,您的结果将与此类似:

Your name is Above-average Boy.
Your super power is:  Flying
Your new stats are:

Brains:  16
Braun:  4
Stamina:  4
Wisdom:  18
Constitution:  16
Dexterity:  12
Speed  2

You created a Mutate!
Your name is Above-average Boy.
Your super power is:  Flying
Your new stats are:

Brains:  16
Braun:  4
Stamina:  4
Wisdom:  18
Constitution:  16
Dexterity:  12
Speed  12

You created a robot! 

Your name is Above-average Boy.
Your super power is:  Flying
Your new stats are:

Brains:  16
Braun:  14
Stamina:  4
Wisdom:  18
Constitution:  16
Dexterity:  12
Speed  2

注意普通超级英雄的速度是 2,机器人也是。然而变异的速度是 12。同样,我们的普通英雄和变异人的布劳恩为 4,而我们的机器人的布劳恩为 14——正如预期的那样。

此时,如果您添加新代码,您的SuperheroClass.py文件应该如下所示——如果不是,请花时间确保它是这样的:

# Import the random module so we can randomly generate numbers
import random

# Create a Superhero class

that will act as a template for any heroes we create
class Superhero():
    # Initializing our class and setting its attributes
    def __init__(self):
        self.superName = superName
        self.power = power
        self.braun = braun
        self.brains = brains
        self.stamina = stamina
        self.wisdom = wisdom
        self.constitution = constitution
        self.dexterity = dexterity
        self.speed = speed

# Adding random values to each stat using the random() function
braun = random.randint(1,20)
brains = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Randomly choosing a super power from the superPowers list
# and assigning it to the variable power

power = random.choice(superPowers)

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Randomizing Super Hero Name
# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

# Creating a subclass of Superhero named Mutate

# Mutate heroes will get a +10 bonus to their speed score.

class Mutate(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a Mutate!")
      self.speed = self.speed + 10

# Creating a subclass of Superhero named Robot
# Robot heroes will get a + 10 bonus to their braun score.

class Robot(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a robot!")
      self.braun = self.braun + 10

# Creating the Superhero object

hero = Superhero()

# We print out the result of the created object, including its parameters
print("Your name is %s." % (hero.superName))
print("Your super power is: ", hero.power)
print("Your new stats are:")
print("")
print("Brains: ", hero.brains)
print("Braun: ", hero.braun)
print("Stamina: ", hero.stamina)
print("Wisdom: ", hero.wisdom)
print("Constitution: ", hero.constitution)
print("Dexterity: ", hero.dexterity)
print("Speed ", hero.speed)
print("")

# Creating a Mutate object

hero2 = Mutate()
print("Your name is %s." % (hero2.superName))
print("Your super power is: ", hero2.power)
print("Your new stats are:")
print("")
print("Brains: ", hero2.brains)
print("Braun: ", hero2.braun)
print("Stamina: ", hero2.stamina)
print("Wisdom: ", hero2.wisdom)
print("Constitution: ", hero2.constitution)
print("Dexterity: ", hero2.dexterity)
print("Speed ", hero2.speed)
print("")

# Create a Robot character

hero3 = Robot()
print("Your name is %s." % (hero3.superName))
print("Your super power is: ", hero3.power)
print("Your new stats are:")
print("")
print("Brains: ", hero3.brains)
print("Braun: ", hero3.braun)
print("Stamina: ", hero3.stamina)
print("Wisdom: ", hero3.wisdom)
print("Constitution: ", hero3.constitution)
print("Dexterity: ", hero3.dexterity)
print("Speed ", hero3.speed)
print("")

添加铃铛和哨子

我们现在需要做的最后一件事是给我们的程序添加一些附加功能。记住,这一章的目标是学习如何使用面向对象的编程来用那些原则重新制作我们的超级英雄生成器 3000 程序;我们的原始版本有一些戏剧性的停顿,并问了用户一些问题。在这里,我们将把所有这些特性添加回我们的程序中,并让他们选择英雄类型。

我们将使用到目前为止在本书中学到的原则,包括if-elif-else语句、random()input()time()模块,当然,还有这一章的 OOP 原则。

作为一个练习,我将重点介绍我们现在要添加的代码的一些主要特性,然后完整地输入程序,供您自己阅读和编码,而不是向您重复代码的每一步。

首先,我们希望为用户提供一个选择,就像我们在最初的程序中所做的那样——主要是,我们询问他们是否想使用超级英雄生成器 3000。如果他们选择“Y”,程序继续;如果没有,循环继续询问他们是否要继续:

# Introductory text

print("Are you ready to create a super hero with the Super Hero Generator 3000?")

# Ask the user a question and prompt them for an answer
# input() 'listens' to what they type on their keyboard
# We then use upper() to change the users answer to all uppercase letters

print("Enter Y/N:")

answer = input()
answer = answer.upper())

# While loop to check for the answer "Y"
# This loop will continue while the value of answer IS NOT "Y"
# Only when the user types "Y" will the loop exit and the program continue

while answer != "Y":
    print("I'm sorry, but you have to choose Y to continue!")
    print("Choose Y/N:")
    answer = input()
    answer = (answer.upper())

print("Great, let's get started!")

同样,这是我们程序的原始版本的代码,我们只是把它添加到了新版本中,所以你应该熟悉它的用法。

接下来,我们要添加一些品牌的新代码。这个新代码的目的是让用户选择他们想要创建的英雄的类型。我们给他们三个选择:常规,变异,或机器人。

# Letting the user choose which type of hero to create
print("Choose from the following hero options: ")
print("Press 1 for a Regular Superhero")
print("Press 2 for a Mutate Superhero")
print("Press 3 for a Robot Superhero")
answer2 = input()

接下来是一个if-elif-else块,它将检查用户答案的值——我们将其存储在变量answer2中——并做出相应的响应。例如,如果用户选择选项 1,将创建一个普通的超级英雄;选项 2,a 变异;等等。

下面是代码块:

if answer2=='1':

    # Creating the Superhero object
    hero = Superhero()

    # We print out the result of the created object, including its parameters
    print("You created a regular super hero!")
    print("Generating stats, name, and super powers.")

    # Creating dramatic effect

    for i in range(1):
        print("...........")
        time.sleep(3)

        print("(nah...you wouldn't like THAT one...)")

    for i in range(2):
        print("...........")
        time.sleep(3)

    print("(almost there....)")
    print(" ")
    print("Your name is %s." % (hero.superName))
    print("Your super power is: ", hero.power)
    print("Your new stats are:")
    print("")
    print("Brains: ", hero.brains)
    print("Braun: ", hero.braun)
    print("Stamina: ", hero.stamina)
    print("Wisdom: ", hero.wisdom)
    print("Constitution: ", hero.constitution)
    print("Dexterity: ", hero.dexterity)
    print("Speed ", hero.speed)
    print("")

elif answer2=='2':
        # Creating a Mutate object
        hero2 = Mutate()
        print("Generating stats, name, and super powers.")

    # Creating dramatic effect

        for i in range(1):
            print("...........")
            time.sleep(3)

            print("(nah...you wouldn't like THAT one...)")

        for i in range(2):
            print("...........")
            time.sleep(3)

        print("Your name is %s." % (hero2.superName))
        print("Your super power is: ", hero2.power)
        print("Your new stats are:")
        print("")
        print("Brains: ", hero2.brains)
        print("Braun: ", hero2.braun)
        print("Stamina: ", hero2.stamina)
        print("Wisdom: ", hero2.wisdom)
        print("Constitution: ", hero2.constitution)
        print("Dexterity: ", hero2.dexterity)
        print("Speed ", hero2.speed)
        print("")

elif answer2=='3':
        # Create a Robot character

        hero3 = Robot()

        print("Generating stats, name, and super powers.")

        # Creating dramatic effect

        for i in range(1):
            print("...........")
            time.sleep(3)

        print("(nah...you wouldn't like THAT one...)")

        for i in range(2):
            print("...........")
            time.sleep(3)

        print("Your name is %s." % (hero3.superName))
        print("Your super power is: ", hero3.power)
        print("Your new stats are:")
        print("")
        print("Brains: ", hero3.brains)
        print("Braun: ", hero3.braun)
        print("Stamina: ", hero3.stamina)
        print("Wisdom: ", hero3.wisdom)
        print("Constitution: ", hero3.constitution)
        print("Dexterity: ", hero3.dexterity)
        print("Speed ", hero3.speed)
        print("")
else:
        print("You did not choose the proper answer! Program will now self-destruct!")

最后,我们还需要import time否则我们的戏剧效果不会起作用!我们在代码的最顶端,在我们的import random语句下面这样做。

新的和改进的超级英雄生成器 3000 代码!

现在我们已经对所有的部分进行了编码,让我们确保它们都是有序的。将您的代码与下面的代码进行比较,确保一切都匹配。然后,运行程序几次,尝试所有选项,看看程序如何工作:

# Import the random module so we can randomly generate numbers
# Import time module for dramatic pausing effect
import random
import time

# Create a Superhero class

that will act as a template for any heroes we create
class Superhero():
    # Initializing our class and setting its attributes
    def __init__(self):
        self.superName = superName
        self.power = power
        self.braun = braun
        self.brains = brains
        self.stamina = stamina
        self.wisdom = wisdom
        self.constitution = constitution
        self.dexterity = dexterity
        self.speed = speed

# Adding random values to each stat using the random() function
braun = random.randint(1,20)
brains = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

# Creating a list of possible super powers

superPowers = ['Flying', 'Super Strength', 'Telepathy', 'Super Speed', 'Can Eat a Lot of Hot Dogs', 'Good At Skipping Rope']

# Randomly choosing a super power from the superPowers list
# and assigning it to the variable power

power = random.choice(superPowers)

# Creating lists of possible first and last names

superFirstName = ['Wonder','Whatta','Rabid','Incredible', 'Astonishing', 'Decent', 'Stupendous', 'Above-average', 'That Guy', 'Improbably']

superLastName = ['Boy', 'Man', 'Dingo', 'Beefcake', 'Girl', 'Woman', 'Guy', 'Hero', 'Max', 'Dream', 'Macho Man','Stallion']

# Randomizing Super Hero Name

# We do this by choosing one name from each of our two name lists
# And adding it to the variable superName

superName = random.choice(superFirstName)+ " " +random.choice(superLastName)

# Creating a subclass of Superhero named Mutate
# Mutate heroes will get a +10 bonus to their speed score.

class Mutate(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a Mutate!")
      self.speed = self.speed + 10

# Creating a subclass of Superhero named Robot

# Robot heroes will get a + 10 bonus to their braun score.

class Robot(Superhero):
    def __init__(self):
      Superhero.__init__(self)
      print("You created a robot!")
      self.braun = self.braun + 10

# Introductory text

print("Are you ready to create a super hero with the Super Hero Generator 3000?")

# Ask the user a question and prompt them for an answer
# input() 'listens' to what they type on their keyboard
# We then use upper() to change the users answer to all uppercase letters

print("Enter Y/N:")

answer = input()
answer = answer.upper())

# While loop to check for the answer "Y"
# This loop will continue while the value of answer IS NOT "Y"
# Only when the user types "Y" will the loop exit and the program continue

while answer != "Y":
    print("I'm sorry, but you have to choose Y to continue!")
    print("Choose Y/N:")
    answer = input()
    answer = answer.upper())

print("Great, let's get started!")

# Letting the user choose which type of hero to create
print("Choose from the following hero options: ")
print("Press 1 for a Regular Superhero")
print("Press 2 for a Mutate Superhero")
print("Press 3 for a Robot Superhero")
answer2 = input()

if answer2=='1':

    # Creating the Superhero object
    hero = Superhero()

    # We print out the result of the created object, including its parameters
    print("You created a regular super hero!")
    print("Generating stats, name, and super powers.")

    # Creating dramatic effect

    for i in range(1):
        print("...........")
        time.sleep(3)

        print("(nah...you wouldn't like THAT one...)")

    for i in range(2):
        print("...........")
        time.sleep(3)

    print("(almost there....)")
    print(" ")
    print("Your name is %s." % (hero.superName))
    print("Your super power is: ", hero.power)
    print("Your new stats are:")
    print("")
    print("Brains: ", hero.brains)
    print("Braun: ", hero.braun)
    print("Stamina: ", hero.stamina)
    print("Wisdom: ", hero.wisdom)
    print("Constitution: ", hero.constitution)
    print("Dexterity: ", hero.dexterity)
    print("Speed ", hero.speed)
    print("")

elif answer2=='2':
        # Creating a Mutate object
        hero2 = Mutate()
        print("Generating stats, name, and super powers.")

    # Creating dramatic effect

        for i in range(1):
            print("...........")
            time.sleep(3)

            print("(nah...you wouldn't like THAT one...)")

        for i in range(2):
            print("...........")
            time.sleep(3)

        print("Your name is %s." % (hero2.superName))
        print("Your super power is: ", hero2.power)
        print("Your new stats are:")
        print("")
        print("Brains: ", hero2.brains)
        print("Braun: ", hero2.braun)
        print("Stamina: ", hero2.stamina)
        print("Wisdom: ", hero2.wisdom)
        print("Constitution: ", hero2.constitution)
        print("Dexterity: ", hero2.dexterity)
        print("Speed ", hero2.speed)
        print("")

elif answer2=='3':
        # Create a Robot character

        hero3 = Robot()

        print("Generating stats, name, and super powers.")

        # Creating dramatic effect

        for i in range(1):
            print("...........")
            time.sleep(3)

        print("(nah...you wouldn't like THAT one...)")

        for i in range(2):
            print("...........")
            time.sleep(3)

        print("Your name is %s." % (hero3.superName))
        print("Your super power is: ", hero3.power)
        print("Your new stats are:")
        print("")
        print("Brains: ", hero3.brains)
        print("Braun: ", hero3.braun)
        print("Stamina: ", hero3.stamina)
        print("Wisdom: ", hero3.wisdom)
        print("Constitution: ", hero3.constitution)
        print("Dexterity: ", hero3.dexterity)
        print("Speed ", hero3.speed) 

        print("")
else:
        print("You did not choose the proper answer! Program will now self-destruct!")

在这一集里!

在这一章中,我们取得了一些令人难以置信的飞跃,因为我们解决了在整本书中讨论的所有主题中最难掌握的概念。没错,相比之下,剩下的就一帆风顺了!

作为一个简短的提醒/未来备忘单,以下是我们在本章中所涉及的内容的总结:

  • OOP 代表面向对象编程。

  • 面向对象编程是一个概念,在这个概念中,我们练习创建可以在我们的程序中重用的代码。

  • 过程化编程包括编写代码,这些代码被设计成——在大多数情况下——逐行或以线性方式执行。

  • OOP 的核心围绕着类、对象和方法。

  • 一个类就像一个蓝图或模板。

  • 对象是一个类的实例。例如,如果一个类是一个家的蓝图,那么对象就是根据这个蓝图创建的实际的房子。

  • 类中使用的函数称为方法。

  • 要定义一个类,我们键入

    班级超级英雄:

    ...一些代码...

  • def 语句用于定义类中的方法。例如:

    定义飞行:

    ...密码...

  • init 用于初始化方法。

  • 当我们创建一个类的实例时,self 用来引用一个参数。

  • 我们通过将对象赋给变量来定义对象,如下所示:

    英雄=超级英雄()

  • 类本质上是分等级的;我们可以有一个主类(父类)和一个子类(子类)。

  • 子类继承父类或超类的方法和参数。

  • 要定义子类,可以使用如下代码:

    职业突变(超级英雄)*

九、其他数据结构简介

欢迎回来萌芽英雄!看起来你已经做了一整天的作业,家务,当然,还有打击犯罪。现在剩下要做的就是吃你的蔬菜,收拾好你的盘子,看在上帝的份上,去刷牙!

当然,你今晚可以一直快速刷牙,这可能会为你赢得一些时间,让你的程序员大脑拥有更多打击犯罪的能力!我是说,毕竟,当你可以给自己编一个程序来帮你咀嚼食物的时候,谁还需要牙齿呢?

不过说真的,去刷牙吧…

这本书现在已经读了一半,你已经为良好的编程实践和实用的语言技能打下了良好而坚实的基础,当你进入职场或独自开发自己的畅销软件时,你可以将这些知识带在身边。

当然,总有更多的东西需要学习。即使你读完这本编程知识的巨著,你的旅程也不会结束。做一名程序员就像做一名学生——你必须不断磨练自己的技能,学习最新最棒的技术。

除了语言更新之外(我们提到过计算机语言更新非常频繁),在某些时候你可能会想尝试其他编程语言和框架。然而,这是不久的将来的另一个篇章。

与此同时,这一章将回顾过去。我们之前讨论了数据结构,学习了如何使用变量和列表。虽然这些都是我们可以用来存储信息的强大工具,但它们并不是我们唯一可用的数据结构。

还有两个需要讨论的:元组字典。这将是这一集的话题。我们还将研究这两个存储单元的一些功能,并将它们整合到一些新程序中。

所以你知道该怎么做——不,不要用你的 x 光眼光去窥探本周数学考试的答案。

刷牙!

然后回到这里,准备学习如何像英雄一样编码。再来一些。

更多数据结构

如上所述,我们已经看到了两种数据结构:列表和变量。我们知道数据结构是保存数据或一条/多条信息的存储容器。我们可以在这些数据结构中存储信息,我们可以删除数据,我们可以向其中添加不同的数据。我们也可以取出数据,将其用于程序的一部分(比喻),然后放回原处(它实际上从未离开过容器)。

一个变量能够保存一段数据。这些数据可以是字母、数字或整数、字符串、句子、段落等等。此外,变量还可以保存列表等对象,这在技术上意味着它们可以保存“一个”以上的数据。同时,一个列表可以包含多条信息。把变量想象成一个文件夹,把列表想象成一个文件柜。

您可能还记得,为了定义变量,我们使用了如下代码:

a = "Hello"
b = 7
c = "Hello, I am being held prisoner in a variable!"

要定义一个列表,我们使用以下方法:

employees = [Big E.', 'Bloke Hogan', 'Alfredo the Butler']
priceList = ['5, 10, 20, 30, 40, 50]

如果我们想从一个变量中打印,我们应该按照下面这样写:

print(a)
print("You have this many apples: ", b)

您也可以使用格式化程序%s作为变量的替代。例如,假设你想写这样一句话:“你有 X 个苹果”,其中X是变量b的值。如果您键入了此代码:

print("You have %s apples!" , b)

运行它时,您会得到以下输出:

You have 7 apples!
To print a list, we can use:

print(employees)

或者打印列表中的单个项目,我们使用它的索引(记住:列表中的第一个项目位于索引0):

print(employees[1])

这将打印出:

Bloke Hogan

既然我们已经回顾了变量和列表,并且稍微刷新了一下关于数据结构如何工作的记忆,那么让我们继续学习 Python 必须提供的其他两种类型的数据结构。

什么是元组?

像列表和变量一样,元组也是一种数据结构。然而,与变量和列表不同,元组被认为是不可变的。这只是一种奇特的说法,即你不能以正常的方式改变它们的值或修改它们。

元组由的有序序列组成。这些项目(或值)在括号中定义,并用逗号分隔。要定义元组,可以使用如下代码:

villains = ('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')

就像列表一样,我们可以使用一个简单的 print()函数打印出元组的内容:

print(villains)

这将导致:

('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')

同样类似于列表,元组中的项目可以通过它们的index号来引用。元组中的项从索引 0 开始。因此,例如,如果我们想要打印我们的villains元组中的第一项,我们将使用:

print(villain[0])

这给了我们一个可怕的恶棍:

Eyebrow Raiser

如果我们想使用反派元组作为句子的一部分,有很多方法可以做到:

# Defining our tuple

villains = ('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')

# Printing the items in a tuple
print(villains)

# Printing single items in a tuple

print(villains[0])
print(villains[1])
print(villains[2])
print(villains[3])

# Ways to append tuple items to sentences

print("The first villain is the sinister", villains[0])
print("The second villain is the terrifying " + villains[1])

给了我们:

('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')
Eyebrow Raiser
Angry Heckler
Not So Happy Man

The Heck Raiser
The first villain is the sinister Eyebrow Raiser
The second villain is the terrifying Angry Heckler

我们使用元组中条目的另一种方式是通过切片它们。当您对一个元组进行切片时,您发出了您希望使用的值的范围。举个例子,这个的格式是villains[0:3]。如果我们运行这段代码:

print(villains[0:3])

输出将是:

('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man')

我知道你在想什么——索引3处的项目是'The Heck Raiser',那么为什么没有打印出来呢?

答案很简单:当我们切片时,冒号前的第一个数字告诉 Python 从哪里开始;后的数字冒号告诉它在该数字前结束

如果我们要写print(villains[0:4]),只有在那时它才会打印出我们所有的四个项目,因为 Python 会在索引4中搜索项目——没有索引——并在它之前打印项目。

请注意,索引的起始编号不一定是 0。例如,如果我们想跳过打印元组中的第一项,我们可以只使用print(villains[1:4]),它将从第二项开始打印:

('Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')

我们可以用元组做的另一个技巧是将它们加在一起。例如,假设您有一个包含闪亮的紫色斗篷的元组和另一个充满圆点斗篷的元组。也许你厌倦了有太多装满斗篷的衣柜,所以你想把它们组合起来。如果是这样,你总是可以把你的元组连接在一起,形成一个全新的元组。考虑这个例子:

# Creating a tuple of my purple capes
purpleCapes = ('Purple Frilly Cape', 'Purple Short Cape', 'Purple Cape with Holes In It')
# Creating a tuple of my Polka Dot capes
polkaCapes = ('Black and White Polka Dot Cape', 'White and Beige Polka Dot Cape', 'Blue Polka Dot Cape Missing the Blue Polka Dots')

# Concatenating - or adding - my two tuples of capes together into a new tuple
allMyCapes = (purpleCapes + polkaCapes)

# Printing out the values of the newly created tuple
print(allMyCapes)

这段代码将元组purpleCapespolkaCapes中列出的条目组合在一起,并将它们存储在一个新创建的名为allMyCapes的元组中。如果您运行这段代码,您将得到:

('Purple Frilly Cape', 'Purple Short Cape', 'Purple Cape with Holes In It', 'Black and White Polka Dot Cape', 'White and Beige Polka Dot Cape', 'Blue Polka Dot Cape Missing the Blue Polka Dots')

注意,这不会改变或影响purpleCapespolkaCapes的值;请记住,您不能更改或修改元组中的值。

除了对元组使用+或串联运算符之外,还可以使用*或乘法运算符来重复存储在元组中的值:

print(allMyCapes[1] * 3)

这将打印出位于allMyCapes元组中索引1处的项目三次,结果是:

Purple Short CapePurple Short CapePurple Short Cape

注意,元组中列出的条目后面没有空格,所以当我们打印它们时,它们没有任何空格。

元组函数

就像列表一样,元组也有一组函数,可以用来与存储在其中的数据进行交互。然而,这些函数并不是元组独有的,可以在 Python 代码的其他地方使用。

两个大家比较熟悉的元组函数应该是min()max();你可能记得在前一章中使用过它们。当在一个元组中使用这两个函数时,它们执行它们通常的角色——也就是说,它们返回元组中的最小值和最大值项。

例如:

# Create a tuple containing a set of numbers
lowest_value = (1, 5, 10, 15, 20, 50, 100, 1000)

# Use the minimum function to return the lowest value item in the tuple
print(min(lowest_value))

该代码将返回:

1

因为从技术上讲,它是元组中最低的值。

如果我们想要最大的数字,我们将使用max()函数:

# Create a tuple containing a set of numbers
highest_value = (1, 5, 10, 15, 20, 50, 100, 1000)

# Use the maximum function to return the highest value item in the tuple
print(max(highest_value))

如你所料,它会返回:1000

另一个有用的元组函数是len(),您可能还记得,它返回字符串的长度或列表中元素的数量。当与元组一起使用时,它返回元组中包含的项数。

# Create a tuple with some items

super_hair = ('Super Stache', 'Macho Beard', 'Gargantuan Goat-tee', 'Villainous Toupee', 'Unfortunate Baldness')

# Print out the number of items in our tuple
print(len(super_hair))

这将返回 5,因为在我们的super_hair元组中总共有五个条目。

使用len()函数的例子包括这样的场景:你需要知道一家公司有多少员工,或者你在退休超级坏蛋的恶棍库里关了多少恶棍。如果您有一个包含这些邪恶角色名字的元组,您可以简单地对其使用len()函数,并快速计算人数。

当然,如果我们想快速查看有多少犯人,返回坏人金库中坏人的数量是有帮助的,但是如果我们想看到以某种顺序打印出来的列表呢——如果有这样的函数就好了……

哦,等等,有!

# A list of Villains Locked Away in the Villainous Vault of Bad Guys
villains = ('Naughty Man ', 'Skid Mark ', 'Mister Millenial ', 'Jack Hammer ', 'The Spelling Bee ', 'Drank All The Milk Man ', 'Wonder Wedgie ', 'Escape Goat')

# Print out a sorted list of our villains tuple

print(sorted(villains))

为了打印一个元组的排序列表(或者多个列表),我们使用了sorted()函数,如前面的代码所示。需要注意一些重要的事情。首先,按字母顺序返回排序结果。第二点——也是最重要的一点——sorted()函数只返回一个排序后的输出——它并不真正对元组中的数据进行排序。记住,元组是不可变的,不能被改变——即使是像sorted()这样强大的函数!

如果我们运行前面的代码,我们的结果将是:

['Drank All The Milk Man ', 'Escape Goat', 'Jack Hammer ', 'Mister Millenial ', 'Naughty Man ', 'Skid Mark ', 'The Spelling Bee ', 'Wonder Wedgie ']

当然,我们可以同样容易地对数字进行排序。考虑以下代码:

# A tuple of numbers we are going to sort
numbers_sort = (10, 20, 5, 2, 18)

# Sorting numbers in our tuple
print(sorted(numbers_sort))

如果我们运行它,它将返回输出:

[2, 5, 10, 18, 20]

当我们看到一个充满数字的元组时,让我们来看看另一个有用的函数——sum()。像到目前为止展示的其他函数一样,sum()也应该为您所熟悉。为了提醒您,它用于对数据结构中的数字求和。

下面是我们用来对一个元组中的项目总数求和的代码:

# A tuple of numbers we are going to sum
numbers_sum = (10, 20, 5, 2, 18)

# Summing items in a tuple
print(sum(numbers_sum))

运行这个程序可以得到numbers_sum元组中的项目总数:55

最后,我们还可以使用tuple()函数将其他数据结构——比如列表和变量——转换成一个元组:

# A list we will convert to a tuple
villainList = ['Naughty Man ', 'Skid Mark ', 'Mister Millenial ', 'Jack Hammer ', 'The Spelling Bee ', 'Drank All The Milk Man ', 'Wonder Wedgie ', 'Escape Goat']

# Using tuple() to convert villainList to a tuple

tuple(villainList)

# A string we will convert to a tuple
villain1 = "Mustached Menace!"
tuple(villain1)

元组更有趣

就在你以为我们和强大的元组的游戏结束了的时候,你发现你中了有奖游戏!在我们学习下一种数据结构之前,我们还需要学习一些东西。

在对元组的介绍中,我们了解到元组在一个非常重要的方面不同于列表:元组是不可变的,其中包含的数据不能以任何方式改变,而列表可以被操作、更新和添加。

如果您关心数据结构的数据完整性,这使得元组成为一个强大的工具。如果你有一组绝对不能改变的条目,那么将它们存储在一个元组中是最合适的。

也就是说,在某些情况下,你可能想从程序中删除一个元组。例如,也许你有一个元组来存储英雄和恶棍可能拥有的所有不同类型的面部毛发。如果这些面部装饰突然(但愿如此)过时了,会发生什么?为了确保元组中的项目不再被访问——并尽可能保持代码的整洁和高效——我们有两个选择。

首先,我们可以简单地用#或" ' ' "注释掉所有引用我们元组的代码。然而,这留下了这样的可能性,有人取消了对你的代码的注释,这可能导致错误或者——上帝保佑——胡须潮流的回归…哦不!

另一种选择是删除或修改引用元组的代码,然后实际删除元组本身。

有一种方法可以让我们删除整个元组;但是,我们不能删除元组中的项目。以下是删除元组的方法:

# A tuple full of facial hair styles for villains and heroes
facial_hair = ('Super Stache', 'Macho Beard', 'Gargantuan Goat-tee', 'Face Mullet',)

# Printing out facial hair
print(facial_hair)

# Using del to delete a tuple entirely
del facial_hair

# Printing out
print(facial_hair)

在这个代码片段中,我们首先创建了facial_hair元组,并给它分配了一堆项——其中一个可怕的项被称为' face mullet '(我甚至不知道这是什么意思)。

接下来,我们打印出facial_hair中的条目,以证明创建元组确实有效。在看到人们愿意在脸上生长的暴行列表后,我们决定最好删除facial_hair元组,假装它从未存在过。我们使用del语句来这样做,如下面的行所示:del facial_hair

最后,为了确保facial_hair真的被删除了,我们再打印一次。当我们运行这段代码时,关于输出会发生两件事。首先,打印出facial_hair中的项目。其次,我们收到一条错误消息。

为什么会出现信息错误?因为我们在第一次打印后就删除了facial_hair;当我们第二次去打印的时候,解释器就再也找不到了。这意味着我们成功地摆脱了世界上的疯狂facial_hair

只是英雄生活中的又一天!

如果运行该程序,您会看到以下结果:

('Super Stache', 'Macho Beard', 'Gargantuan Goat-tee', 'Face Mullet')
Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/TupleExamples.py", line 101, in <module>
    print(facial_hair)
NameError: name 'facial_hair' is not defined

有时当我们使用元组存储数据时,我们可能需要知道某个特定的项在我们的数据结构中出现了多少次。例如,单词“Mississippi”中有很多臭名昭著的 I。字母“s”也是如此。如果我们创建一个包含这个单词的元组,我们可以计算这个单词中同时出现“I”和“s”的次数,这样当人们要求我们告诉他们一些有趣的事情时,我们可以说,“你知道密西西比州有一堆 s 和 I 吗?真人真事,老弟!”

为了计算一个条目在元组中出现的次数,或者计算等于 s 的条目的数量,我们使用了count()方法。

# Tuple containing all of the letters used to spell Missisisippi
state = ('M', "i", "s", "s", "i", "s", "i", "s", "i", "p", "p", "i")
# Note: You could, technically, also easily create the tuple using state = tuple(‘Missisisippi’) with the tuple() command, which automatically converts a string into a tuple.
# Count the number of times "i" appears in our tuple and print out the result
print("There are this many of the letter i in Missisisippi: ")
print(state.count('i'))

# Count the number of times "s" appears in Missisisippi
print("There are this many of the letter s in Missisisippi: ")
print(state.count('s'))

代码state.count('i')中括号中的字符告诉 Python 计算‘I’在状态元组中出现的次数。

如果我们运行这个示例代码,我们将得到以下输出:

There are this many of the letter i in Missisisippi
5
There are this many of the letter s in Missisisippi
4

我们还可以使用关键字in在元组中搜索一个条目。该关键字主要询问值“x”是否是元组中的:

# Tuple containing all of the letters used to spell Missisisippi
state = ('M', "i", "s", "s", "i", "s", "i", "s", "i", "p", "p", "i")
# Checking to see if "z" or "i" appears in our state tuple
print('z' in state)
print('i' in state)

当检查一个条目是否包含在一个元组中时,in关键字返回一个布尔(真或假)响应。当我们运行这段代码时,它返回输出:

False
True

因为它首先检查在state元组中是否有一个'z',结果发现没有(False)。然后它在状态元组中检查一个'i',当然会找到一个或多个(True)。

元组示例

到目前为止,在本章中我们已经讨论了很多使用元组的方法,所以为了方便起见,下面你可以找到一个 Python 样本文件,其中包含了到目前为止在本章中编写的与元组相关的所有代码。

您可以随意修改这段代码,并查看更改已定义元组中的项目如何影响代码片段及其结果:

# Defining our tuple

villains = ('Eyebrow Raiser', 'Angry Heckler', 'Not So Happy Man', 'The Heck Raiser')

# Printing the items in a tuple
print(villains)

# Printing single items in a tuple

print(villains[0])
print(villains[1])
print(villains[2])
print(villains[3])

# Ways to append tuple items to sentences

print("The first villain is the sinister", villains[0])
print("The second villain is the terrifying " + villains[1])

# Slicing starting at index 0 and ending before the item at index 3
print(villains[0:3])

# Slicing starting at index 1 and ending before the item at index 4
print(villains[1:4])

# Creating a tuple of my purple capes
purpleCapes = ('Purple Frilly Cape', 'Purple Short Cape', 'Purple Cape with Holes In It')
# Creating a tuple of my Polka Dot capes
polkaCapes = ('Black and White Polka Dot Cape', 'White and Beige Polka Dot Cape', 'Blue Polka Dot Cape Missing the Blue Polka Dots')

# Concatenating - or adding - my two tuples of capes together into a new tuple
allMyCapes = (purpleCapes + polkaCapes)

# Printing out the values of the newly created tuple
print(allMyCapes)

# Print the item listed at index 1, 3 times
print(allMyCapes[1] * 3)

# Create a tuple containing a set of numbers
lowest_value = (1, 5, 10, 15, 20, 50, 100, 1000)

# Use the minimum function to return the lowest value item in the tuple
print(min(lowest_value))

# Create a tuple containing a set of numbers
highest_value = (1, 5, 10, 15, 20, 50, 100, 1000)

# Use the maximum function to return the highest value item in the tuple
print(max(highest_value))

# Create a tuple with some items

super_hair = ('Super Stache', 'Macho Beard', 'Gargantuan Goat-tee', 'Villainous Toupee', 'Unfortunate Baldness')

# Print out the number of items in our tuple
print(len(super_hair))

# A tuple of Villains Locked Away in the Villainous Vault of Bad Guys
villains = ('Naughty Man ', 'Skid Mark ', 'Mister Millenial ', 'Jack Hammer ', 'The Spelling Bee ', 'Drank All The Milk Man ', 'Wonder Wedgie ', 'Escape Goat')

# Print out a sorted list of our villains tuple

print(sorted(villains))

# A tuple of numbers we are going to sort
numbers_sort = (10, 20, 5, 2, 18)

# Sorting numbers in our tuple
print(sorted(numbers_sort))

# A tuple of numbers we are going to sum
numbers_sum = (10, 20, 5, 2, 18)

# Summing items in a tuple
print(sum(numbers_sum))

# A list we will convert to a tuple
villainList = ['Naughty Man ', 'Skid Mark ', 'Mister Millenial ', 'Jack Hammer ', 'The Spelling Bee ', 'Drank All The Milk Man ', 'Wonder Wedgie ', 'Escape Goat']

# Using tuple() to convert villainList to a tuple

tuple(villainList)

# A string we will convert to a tuple
villain1 = "Mustached Menace!"
tuple(villain1)

# A tuple full of facial hair styles for villains and heroes
facial_hair = ('Super Stache', 'Macho Beard', 'Gargantuan Goat-tee', 'Face Mullet',)

# Printing out facial hair
print(facial_hair)

# Using del to delete a tuple entirely
del facial_hair

# Printing out facial_hair to show that it is now empty
# print(facial_hair)

# Tuple containing all of the letters used to spell Missisisippi
state = ('M', "i", "s", "s", "i", "s", "i", "s", "i", "p", "p", "i")

# Count the number of times "i" appears in our tuple and print out the result
print("There are this many of the letter i in Missisisippi: ")
print(state.count('i'))

# Count the number of times "s" appears in Missisisippi
print("There are this many of the letter s in Missisisippi: ")
print(state.count('s'))

# Checking to see if "z" or "i" appears in our state tuple
print('z' in state)
print('i' in state)

# Looping through the previously created villainList tuple and printing out each item
for var in villainList:
    print(var)

使用字典

Python 有另一种数据结构,称为字典。字典与列表、变量和元组的区别非常有趣。尽管列表和元组的数据项存储在特定的索引中,因此可以在这些引用号处被引用(从索引 0 开始),但字典依赖于所谓的映射

映射是 Python 存储数据的一种方式,其中 Python 将keys映射到values。这就是所谓的键值对。

keys定义在密钥对值的左侧,通常与右侧的value相关或描述它们。Keys是不可变的,不能改变,而values是可变的,可以由任何数据类型组成。

要定义一个字典,您需要给它一个名称,然后将存储在字典中的数据用两个大括号{}括起来:

algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

在这种情况下,我们可以说algebro字典代表邪恶的恶棍,数学大师阿尔盖布罗!作为我们超级恶棍数据库的一部分,我们记录了所有不友好的邻居恶棍。在我们的字典中,我们有一些信息——即他们的代号、权力和真实姓名。我们在字典中通过命名我们的键来表示这些数据,以匹配它们将与之配对的数据。

因此,在这个例子中,例如,codename是一个键,Algebro是属于那个键的值。在我们的algebro字典中,它们将组成一个键值对。

algebro字典中的其他键值对是:

  • 权力:数学

  • 实名:艾尔。g .兄弟

如果我们想打印出字典,我们会使用:

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

# Print out the algebro dictionary
print(algebro)

产生的输出是:

{'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

字典中的键值对也可以称为元素或数据项,并且是未排序的。如您所料,它们也可以单独打印或调用。假设我们只想知道阿尔杰布罗的真名。要仅打印字典中特定键的值,我们应该编写:

print(algebro['real-name'])

Python 将返回结果:

Al. G. Bro.

字典方法

字典有几个内置的方法,我们可以用它们来与键和值进行交互。假设我们想看看字典中有哪些键。为了打印出来,我们将使用dict.keys()方法:

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

# Print just the keys in the algebro dictionary
print(algebro.keys())

运行时,我们得到的输出是:

dict_keys(['codename', 'power', 'real-name'])

如果我们只想访问algebro字典的值,我们将使用dict.values()方法,如下所示:

# Print just the values in the algebro dictionary
print(algebro.values())

给了我们:

dict_values(['Algebro', 'Mathemagics', 'Al. G. Bro.'])

但是如果我们想同时打印键和值呢?有一个方法也可以做到这一点,称为 dict.items()方法:

# Print the key-value pairs
print(algebro.items())

产量?

dict_items([('codename', 'Algebro'), ('power', 'Mathemagics'), ('real-name', 'Al. G. Bro.')])

当我们需要比较数据或查看字典中有哪些数据时,以这种方式使用字典方法非常有用。我们还可以将我们的关键字及其相关数据与其他字典进行比较。例如,恶棍阿尔杰布罗可能会出现在几本different字典中。一个可能存储了他的超能力和秘密身份的信息,而另一个字典可能包含他的高中记录和他在体育课上的成绩(相信我,数学魔术师阿尔杰布罗在高中体育课上很糟糕!).

*最后,还有一种方法可以打印出字典中的数据项——我们可以简单地迭代(或循环)字典,在每次迭代中打印出信息。还记得for循环吗?它在这里会派上用场:

# Using a for loop to iterate through and print out our dictionary

for key, value in algebro.items():
    print("The key is: ", key, " and the value is: ", value)

这个有用的代码片段会产生更加友好的输出:

The key is:  codename  and the value is:  Algebro
The key is:  power  and the value is:  Mathemagics
The key is:  real-name  and the value is:  Al. G. Bro.

字典带来更多乐趣

与元组不同,字典值——尽管不是键——可以修改。比方说,我们想给我们的阿尔杰布罗恶棍添加一个年龄。为此,我们可以简单地使用如下代码:

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}
# Add the key 'age' to the dictionary 'algebro' and assign it the value '42'
algebro['age'] = 42'

# Print out algebro to show the newly added key-value pair
print(algebro)

运行这段代码时,我们得到的结果是:

{'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.', 'age': '42'}

我们在这里可以看到,我们的新键值对'age''42'已经被添加。

这里你可能注意到的问题是age不是一个静态的数字;也就是说,它随时间而变化。每当我们的反派角色 Algebro 过生日时,我们都必须更新这个键值对。

不用担心,因为修改键值和添加新键值一样简单:

# Updating a the value for our 'age' key
algebro['age'] = 43

# Printing the algebro dictionary to see the updated value of the 'age' key
print(algebro)

现在,如果我们打印出age的值,它将等于:43

我们可以更新字典值的另一种方法是使用dict.update()方法。例如,我们也可以添加一个名为 villainType 的新键,并使用dict.update()方法给它一个成对的值mutate,如下所示:

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

# Using dict.update() to add a key-pair value to our 'algebro' dictionary
# Note the use of curly braces {}, mixed with parentheses ()
algebro.update({'villainType': 'mutate'})

# Printing out the results
print(algebro)

现在,如果您运行这段代码,输出将是:

{'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.', 'age': 43, 'villainType': 'mutate'}

注意添加了键-值对villainType mutate。另请注意,您还可以使用这个方法,使用相同的代码来更新字典中任何现有的键值对。

使用del关键字——我们以前见过——我们可以从字典中删除一个键值对。例如,如果出于某种原因,Algebro 失去了他的超能力,我们可以像这样删除整个键值对:

# Using the del keyword to delete a key-value pair
del algebro['power']

# Printing algebro to verify that we properly removed the key-value pair
print(algebro)

这给了我们:

{'codename': 'Algebro', 'real-name': 'Al. G. Bro.', 'age': 43, 'villainType': 'mutate'}

验证我们确实成功删除了键power及其相关值。

此外,如果我们想要删除整个字典,我们也可以使用del来删除:

# Deleting the algebro dictionary using the del keyword

del algebro

# Printing the deleted algebro, which results in an error
# This occurs because algebro no longer exists
print(algebro)

如果您运行该代码,您将得到一条错误消息,因为您现在正试图打印我们之前已经删除的algebro字典:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/DictionaryExamples.py", line 58, in <module>
    print(algebro)
NameError: name 'algebro' is not defined

最后,有时您可能希望删除字典中的所有条目或键值对,但是而不是删除字典本身。为此,我们使用 dict.clear()方法:

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

algebro.clear()
print(algebro)

如果您运行这段代码,您将得到以下输出:

{}

或者说,基本上就是一本空字典。或者,您可以通过简单地键入:algebra = {}来达到相同的效果。

其他词典方法

总的来说,大约有 26 种字典方法供你使用;篇幅不允许我在本书中涵盖所有这些问题;然而,我强烈建议你拓展自己的研究领域。尝试它们,明智地使用你新发现的能力!

这些方法中的一些已经在列表和元组中使用过;其中包括 sum()、min()、max()、sorted()等等。

这里有一个其他字典方法的列表:大胆尝试吧!

  • dict.clear():删除字典中的所有条目

  • dict.copy():返回字典的副本

  • dict.fromkeys():用于从序列中创建字典

  • 返回指定键的值

  • dict.items():返回给定字典的键/对值的视图

  • dict.keys():返回字典中的键

  • popitem():返回并删除一个字典元素

  • pop():返回并删除指定键中的元素

  • dict.setdefault():检查一个键是否存在,如果不存在,插入这个键(用一个值)

  • dict.values():返回字典中的所有值

  • dict.update():用于更新字典

您可以在字典上使用的其他方法包括:

  • any():测试 iterable 的元素是否为 True。

  • all():如果 iterable 的所有元素都为 True,则返回 True。

  • dict():用于创建字典。

  • enumerate():创建或返回一个枚举对象。

  • iter():返回给定对象的迭代器。

  • len():返回对象的长度。

  • max():返回最大的元素。

  • min():返回最小的元素。

  • sorted():返回一个排序列表。

  • sum():对所有项目求和。

示例字典代码

这是一个包含本章所有代码的样本文件。请随意对代码进行任何修改和实验(疯狂地)。注意任何错误,并尝试用有趣的方式修改它,利用你在书中学到的知识。

记住,玩得开心,有冒险精神(毕竟,不然怎么会是超级英雄呢?):

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

# Print out the algebro dictionary
print(algebro)

# Print out just the real-name key's value
print(algebro['real-name'])

# Print just the keys in the algebro dictionary
print(algebro.keys())

# Print just the values in the algebro dictionary
print(algebro.values())

# Print the key-value pairs
print(algebro.items())

# Using a for loop to iterate through and print out our dictionary

for key, value in algebro.items():
    print("The key is: ", key, " and the value is: ", value)

# Add the key 'age' to the dictionary 'algebro' and assign it the value '42'
algebro['age'] = '42'

# Print out algebro to show the newly added key-value pair
print(algebro)

# Updating a the value for our 'age' key

algebro['age'] = 43

# Printing the algebro dictionary to see the updated value of the 'age' key
print(algebro)

# Using dict.update() to add a key-pair value to our 'algebro' dictionary
# Note the use of curly braces {}, mixed with parentheses ()
algebro.update({'villainType': 'mutate'})

# Printing out the results
print(algebro)

# Using the del keyword to delete a key-value pair
del algebro['power']

# Printing algebro to verify that we properly removed the key-value pair
print(algebro)

########################################################
# This section of code is commented out because it will cause everything error
# Deleting the algebro dictionary using the del keyword
# del algebro

# Printing the deleted algebro, which results in an error
# This occurs because algebro no longer exists

#print(algebro)
################################################

# Create a dictionary name algebro and fill it with key-value pairs
algebro = {'codename': 'Algebro', 'power': 'Mathemagics', 'real-name': 'Al. G. Bro.'}

algebro.clear()
print(algebro)

在这一集里!

你应该为自己能走到这一步而感到骄傲!在这一集里,我们通过在你的记忆库中加入两种新的数据结构——元组和字典,扩展了你的大脑存储容量!

我们讲了很多,所以,像往常一样,用一个可爱的列表来总结我们在这一章中学到的大部分知识总是一个好主意。你猜怎么着?这是:

  • 除了变量和列表,元组和字典是另外两种保存信息的数据结构形式。

  • 元组类似于列表,只是元组是不可变的;也就是说,不能更改或修改它们的值。

  • 元组以这种方式定义:

    恶棍=('提眉者','愤怒的质问者','不太高兴的人','见鬼的提眉者')

  • 我们可以使用 print(恶棍)打印一个元组。

  • 我们使用:print(恶棍[0])打印元组中的一个条目,这将打印元组中的第一个条目——或者索引为 0 的条目。

  • 为了打印一个元组中的一系列项,我们使用:print(throughts[0:3]),它将打印位于索引 0、1 和 2 的项;它在位于第二个参数(本例中为 3)的项目之前结束打印。

  • 元组函数包括 min()、max()、len()、sorted()、sum()和 Tuple()。

  • del 关键字可用于删除整个元组。

  • count()计算元组中出现的实例数。

  • 我们可以使用in来检查某个东西是否出现在一个元组中;它返回一个布尔值真或假。

  • 字典使用映射来存储数据。

  • 字典包含一个键值对或一组键值对,也称为元素或数据项。

  • 键定义在冒号的左边,而值定义在右边。

  • 字典是这样定义的:

    algebro =

  • 您可以使用:print(algrebro)打印词典。

  • 您可以使用:print(algebro['real-name'])打印特定键的值。

  • 字典方法包括 dict.keys()、dict.items()和 dict.update()。

  • del 关键字也可以用来删除字典。

  • dict.clear()允许您从字典中清除元素,而不删除实际的字典(只是它的键和值对)。*

十、Python 文件

到目前为止,我们主要在一个文件中工作;也就是说,我们所有的代码都保存在一个单独的.py文件中,并从同一个文件中运行。然而,在现实世界中,我们的许多程序将存储在多个文件中。更重要的是,我们很可能会将一些我们喜欢的代码片段和函数保存在文件中以备后用。这就是我们程序员的工作方式,现在也包括你。

我们使用多个代码文件有很多原因。其中一些以效率和减少代码中的错误为中心——还记得我们关于保存处理常见任务的程序部分以便以后在其他程序中重用的全部内容吗?当我们谈到函数和模块时,我们深入地讨论了这一点。

我们还可以选择保存类和对象、变量、数据列表,以及我们能想到的任何类型的常用代码。基本上,如果你认为你以后会在程序中用到某个东西,并且它会节省你的时间,减少用户输入的错误(也就是说,当你因为打击犯罪而疲惫的时候输入代码),那么就帮你自己一个大忙,把它复制到一个单独的文件中以备后用。

哦,一定要把它完整地记录下来,这样你就知道你保存这些代码是为了什么了!

我们使用来自多个文件的代码的另一个原因与这样一个事实有关——在更大的项目中也是如此——通常我们并不是一个程序中唯一的编码者。我们可能只处理整个应用的一小部分。仅仅因为这个原因,你可能会发现自己在处理过多的文件。

例如,如果你正在编写一个超级英雄角色扮演游戏,你可能会监督整个项目。你的朋友保罗·考德曼可能负责处理与战斗有关的那部分代码。你的另一个朋友 Ralph Programmerdudeson 可能会处理角色创建。你的办公室克星(每个人都需要一个)可能只是坐在角落里,整天愤怒地瞪着你,吃着数量可疑的快餐。

为了把程序组合在一起,你可以从 Paul Coderman 的文件中调用一组函数,从你的孩子 Ralph Programmerdudeson 的充满代码的文件夹中插入角色创建引擎。最后,你的仇人会增加他的愤怒和尖酸。结合起来,你将拥有一个成功的角色扮演游戏所需要的所有元素。

在 Python 中使用文件

如果您已经在本书中读到这里,我们将理所当然地认为您知道什么是文件系统。如果没有,就想想你电脑桌面上那些储存文档、漫画、视频游戏和大量自拍照的小文件夹。

当我们最初安装 Python 时,我们让它安装在默认位置。根据你的电脑,操作系统和你的硬盘设置方式,你可能会有一些和我的非常相似的东西。例如,我的 Python 和 IDLE 实例安装在:

C:\Users\James\AppData\Local\Programs\Python\Python36-32

你的可能有点不同,比如:

C:\Users\YourName\Programs\Python

诸如此类。

顺便提一下,我使用 IDLE 创建的所有.py或 Python 文件都自动存储在这个相同的位置。事实上,当我运行一个程序时,它首先搜索这个文件夹,寻找文件。如果我从我创建的 Python 程序中调用另一个文件,它会自动搜索这个文件夹,并期望在这里找到它。

下面是我的 Python 目录文件夹的一个例子,展示了我迄今为止为这本书写的所有文件(见图 10-1 ):

img/468718_1_En_10_Fig1_HTML.jpg

图 10-1。

Python 目录文件夹的示例

因为这些文件都在我们称之为root的目录中,当我把它们调入我的一个 Python 程序时,我不需要做任何特别的事情,比如改变目录或查看其他文件夹;我所要做的就是在程序中命名这个文件,然后它就把它导入——easy-peasey,mac-n-cheesey。

马上回来,我现在要去吃芝士通心粉了。

好吧,我回来了。

在现实生活中,事情并不总是这么简单。我们通常将每个程序的程序文件保存在特定的文件夹中,这样我们就不会混淆或意外调用错误的文件。你可以想象,在一年的时间里,你可能会积累相当多的文件,你肯定需要一种方法来组织你的工作。

例如,如果你正在开发超级英雄角色扮演游戏,你可能有一个名为超级英雄角色扮演游戏的主文件夹。然后,在那个文件夹中,你会有一组文件夹,用来存放游戏每个部分的文件。例如,考虑这种文件夹结构:

  • 超级英雄 PG
    • 字符创建模块

    • 战斗引擎

    • VillainProfiles

    • 区域文件

    • RandomEncounterFunctions

    • 项目列表

    • 超级大国

    • 村庄词典

    • 英雄阶层

    • 使突变

    • 人类

    • 机器人

    • 魔术师

    • 侧踢侧面

等等。这些文件夹中的每一个都保存着你的程序的片断,这些片断执行了程序的每一个部分的功能。例如,BattleEngine文件夹将保存负责处理战斗场景、伤害结果等的函数和代码。

由于所有这些文件都存储在root文件夹的之外的中,我们需要从该部分代码所在的目录中调用主程序中的文件。

如果此刻这看起来令人困惑,那也没关系;我们将在这一章中详细讲述如何从另一个程序中调用一个程序——不管它在哪里。

既然您已经熟悉了文件夹结构和 Python 文件可能存储在不同位置的基本概念,剩下的事情就很容易了。

嗯……蛋糕。马上回来,去吃点蛋糕。

文件类型

到目前为止,我们只和。py 文件。实际上,我们可以用文本或。txt 文件,这是大多数程序员所做的,依赖于程序,如 Windows 的记事本或另一个更令人印象深刻的文本编辑器 Notepad++。我们将在本书的最后两章讨论一些你可以用来编码的工具;现在,要知道我们主要处理的是。py 文件。

当你扩展你的编程范围,开发你自己的程序,或者开始为一家公司工作时,你也会开始涉及到其他的文件类型。其中最常见的是。txt、超文本标记语言(HTML)(用于开发网页)和逗号分隔值(CSV)文件——想想电子表格数据。

当然,您也可以使用其他语言文件,比如 C 或 C++ 文件和 JSON。这就是所谓的扩展 Python,也是我们在第十三章简要介绍的一个主题。

对于本章中的例子,我们将主要使用。txt 和。py 文件,但是大部分理论都适用。

用 Python 代码创建文本文件

我们有几种方法可以接近这本书的下一部分。对于初学者,我们可以简单地打开一个记事本或文本编辑器程序,创建一个新的文本文件,然后将它保存到与所有其他文件(当前)相同的目录中。py 和 Python 编程文件保存到。但那似乎有点懒。相反,让我们用不同的方法——让我们用一些 Python 代码创建一个新的文本文件。

我们将在这一部分学习一些新概念,所以如果事情没有马上发生,不要太担心;在我们了解了核心概念之后,我们将会非常全面地介绍所有的内容。此外,请务必——一如既往——阅读注释代码,以便了解每一行的含义。

记住:我们在这个程序中的目标是使用 Python 创建一个新的文本文件。这些不同于。到目前为止,我们一直在创建 py 或 Python 文件。这里的技巧是,我们将从我们的 Python 文件中创建一个文本文件,所以请确保您不会混淆我们正在处理哪个文件。

首先,我们需要创建一个名为FunWithFiles.py的新 Python 文件。向其中添加以下代码:

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!")

# The close() function closes the file we are working on and saves it
# It is important to always close a file when we are finished with it
# To ensure we do not make any additions or mess up the file in anyway
newFile.close()

这段代码中有几点需要注意。首先,我们这里的目的是使用代码创建一个新的文本或。名为CreatedFile.txt的 txt 文件。我们首先创建一个名为newFile的变量,并对其应用open()函数。通常,我们使用open()来做您认为它可能会做的事情——打开一个文件,以便我们可以对它采取某种行动。然而,在这个例子中,因为 Python 找不到名为CreatedFile.txt的文件,所以它继续假设我们想要创建一个新的。txt 文件,这样做。请注意,即使存在同名文件,它也会覆盖现有文件并在其中保留空白,因此使用这种方法时要小心!

在生产线上:

open("CreatedFile.txt", 'w')

"CreatedFile.txt"是我们希望打开/创建的文件的名称。'w'部分被称为参数,是我们可以在open()函数中使用的几个参数之一。

在这种情况下,'w'告诉 Python,您希望打开文件来写;因此,Python 在写模式下打开文件。这种模式允许我们对所讨论的文件进行更改或添加内容。

或者,我们可以使用'x'模式,它允许我们创建并写入一个新文件。但是,它以独占方式创建文件,这意味着如果文件名已经存在,它将失败并导致错误。要使用它,我们只需将代码改为:

open("CreatedFile.txt", 'x')

接下来,在我们的代码中,我们想要向新创建的文件中添加一些内容;当然,我们没有必要这样做,我们可以让它保持空白。然而,我们也可以在打开的时候放些东西进去。

该行中的.write方法:

newFile.write("Look, we created a brand new file using Python code!")

用于存储或写入文本“看,我们使用 Python 代码创建了一个全新的文件!”到新创建的CreatedFile.txt文件中。

最后,我们总是希望在完成后关闭我们打开或创建的任何文件,以确保它不会以任何我们不希望的方式被损坏、更改或影响。为此,我们使用了close()函数,如下所示:

newFile.close()

用 Python 读取文件

除了创建文件和写入文件之外,我们还可以读取文件。现在我们已经创建了新文件CreatedFile.txt,让我们创建一个程序来读取它。将以下代码添加到您的FunWithFiles.py文件中:

# Open the file CreatedFile.txt
read_me_seymour = open("CreatedFile.txt", 'r')

# Read the contents of the file

print(read_me_seymour.read())

这里,我们使用了open()来打开我们之前创建的文件,并向它传递了'r'或 read 参数。然后,我们使用了print()函数。 read 方法将文本打印到屏幕上,这样我们就可以看到我们文件的内容。

当我们在一个文件中只有一行文本时,这很好,但是如果我们有多行呢?

更改FunWithFiles.py文件中的代码,使其与以下示例相匹配:

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
# Remember, if the file name already exists, it will overwrite the existing one, erasing its contents in the process.
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!")
newFile.write("Here is a second line of text!")

# The close() function closes the file we are working on and saves it
# It is important to always close a file when we are finished with it
# To ensure we do not make any additions or mess up the file in anyway
newFile.close()

# Open the file CreatedFile.txt
read_me_seymour = open("CreatedFile.txt", 'r')

# Read the contents of the file

print(read_me_seymour.read())

我们添加到代码中的只有这一行:

newFile.write("Here is a second line of text!")

当我们运行该文件时,我们期望看到两行文本,例如:

Look, we created a brand new file using Python code!
Here is a second line of text!

然而,事实并非如此。相反,我们得到的输出是:

Look, we created a brand new file using Python code!Here is a second line of code!

但这是为什么呢?

有两个答案,我们都会讨论。首先,当我们最初向新创建的文件中写入文本时,我们没有为它提供任何格式;。write 不在文本末尾使用回车符或换行符(相当于您在键入一个句子后按下 Enter 按钮)。

为了确保我们的行不会连在一起,因此,我们必须确保在我们的文本末尾添加一个\n 换行符。本质上,你想修改这两个。编写如下语句:

newFile.write("Look, we created a brand new file using Python code!\n")
newFile.write("Here is a second line of text!\n")

继续更改您的FunWithFiles.py文件,使其与这些更改相匹配。现在尝试再次运行该程序。这一次,你应该有结果了:

Look, we created a brand new file using Python code!
Here is a second line of text!

使用 readline()和 readlines()

有时候,您只想读取文本文件中的一个或几个特定行。.read方法读取文件的全部内容,因此在这个场景中不适用。相反,我们需要使用 readlines()。

为了看到这一点,让我们修改我们的代码

print(read_me_seymour.read())

print(read_me_seymour.readline())

现在,当您运行该程序时,您的结果将是:

Look, we created a brand new file using Python code!

这是因为readline()一次只读取一行文本。要读取文件中的下一行文本,只需添加另一个readline()实例。继续操作,确保您当前的FunWithFiles.py副本与此代码匹配:

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!\n")
newFile.write("Here is a second line of text!\n")

# The close() function closes the file we are working on and saves it
# It is important to always close a file when we are finished with it
# To ensure we do not make any additions or mess up the file in anyway
newFile.close()

# Open the file CreatedFile.txt
read_me_seymour = open("CreatedFile.txt", 'r')

# Read the contents of the file

# Read the first line in the txt file
print(read_me_seymour.readline())

# Read the second line in the txt file
print(read_me_seymour.readline())

# Close the file again
read_me_seymour.close()

除了 readline()之外,还有一个名为 readlines()的函数,尽管看起来几乎相同,但它的操作略有不同。如果我们改变我们的代码(不要)说print(read_me_seymour.readlines()),而不是从我们指定的 txt 文件中打印出一行文本,它将打印出文件中的一系列行。结果会是这样的:

['Look, we created a brand new file using Python code!\n', 'Here is a second line of text!\n']

关于读写文件的警告

在我们进一步学习之前,我们应该讨论一下写入文件是如何工作的。当您第一次写入文件时,一切都很好。但是,如果我们尝试打开一个文件并第二次写入它——使用“w”参数——您实际上将覆盖您尝试写入的文件中当前存在的任何内容。

例如,如果您编写了代码:

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!\n")
newFile.write("Here is a second line of text!\n")

# Opening the File to add more text
addingToFile = open("CreatedFile.txt", 'w')

# Writing more text
addingToFile.write("This is new text.\n")

addingToFile.close()

并试图打印出结果,你认为结果会是什么?

虽然您可能认为它是类似于以下内容的东西:

Look, we created a brand new file using Python code!
Here is a second line of text!
This is new text.

这是错误的。实际上,当我们第二次打开文件并开始写入时,我们会覆盖任何已经存在的文本并插入新的文本行。在这种情况下,真正的答案应该是:

This is new text.

所以,这个故事的寓意很简单:当你处理文件的时候,一定要知道你处于什么模式。

附加到文件

为了解决如何在不覆盖文件中任何现有文本的情况下写入文件的难题,我们只需从'w'参数切换到'a'或 append 参数。

假设我们想在文件FunWithFiles.py.中添加另一行文本,我们需要做的就是重新打开文件,进入追加模式。让我们修改我们的程序,使其符合以下内容:

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!\n")
newFile.write("Here is a second line of text!\n")

# The close() function closes the file we are working on and saves it
# It is important to always close a file when we are finished with it
# To ensure we do not make any additions or mess up the file in anyway
newFile.close()

# Open the file CreatedFile.txt
read_me_seymour = open("CreatedFile.txt", 'r')

print("THE ORIGINAL TEXT IN THE FILE")
print(read_me_seymour.readline())
print(read_me_seymour.readline())

# Closing the file
read_me_seymour.close()

# Opening the file again to write some text to it
addingToFile = open("CreatedFile.txt", 'a')

# Adding some text to the file in append mode
addingToFile.write("This is new text.")

# Closing the file
addingToFile.close()

# Opening the file yet again, to read it
# Now that we have appended a line

print("THE TEXT IN THE FILE AFTER WE APPEND")
appendedFile = open("CreatedFile.txt", 'r')

# This is another way we can print from a file
# Here we are using a for loop
# And using the keywords in and line to print each line
# In the text file

for line in appendedFile:
    print(line)

# Closing the file again
appendedFile.close()

我们在这一轮做了相当多的补充。然而,由于可靠的文档实践,应该相当清楚做了什么更改以及它们做了什么。

尽管如此,我们还是来讨论一下添加的一些代码。

首先,简要概述代码及其用途。该守则的目的是:

  • 创建新的 txt 文件

  • 向文件中写入两行文本

  • 以读取模式打开文件以读取文件

  • 打印出文件中的行

  • 以追加模式打开文件

  • 向文件追加新的一行文本

  • 打印出修改文件的内容

在这些步骤之间,我们还关闭了文件。所以对于每一个打开读、写或追加的实例,我们总是想确定我们练习了良好的编码并关闭了文件。这可能不是对文件进行编码的最有效的方式,但是对于我们这里的目的——简单地学习基本语言、编码原则和理论——这是最好的方式。

最后,您可能已经注意到,我们在代码末尾附近偷偷加入了一个小的for循环。这是我们打印文本文件中的行的另一种方式。

使用目录

正如我们前面讨论的,到目前为止,我们只在最初安装 Python 的目录中工作。在本节中,我们将学习如何打开计算机上其他文件夹或目录中的文件。

然而,在我们这样做之前,让我们看一个简单的方法来确定我们当前在哪个目录中。创建一个名为WorkingWithDirectories.py的新 Python,并键入以下代码:

# Import the module os
# This is used to work with operating system information
import os

# Use the getcwd() method of the os module
# To see what directory we are in
os.getcwd()

当你运行这段代码时,你会得到一个类似于我的结果;它会有所不同,因为我们的计算机系统和设置是不同的,但它应该是这样的:

C:\Users\James\AppData\Local\Programs\Python\Python36-32

这是手头上的重要信息,因为我们可能在不同的目录中有文件。如果我们试图打开当前目录中的一个文件,而它并不存在,我们将要么以一个错误结束,要么意外地创建该文件的一个新版本。当然,如果我们在不同的目录中有一个文件的多个副本,这会使事情变得混乱。

现在我们知道了当前的目录,我们可以切换到另一个目录并从那里打开一个文件。我说“可能”是因为在我们实际尝试之前,我们需要创建一个新的目录来更改。如果你还记得,在这一章的开始,我向你展示了我当前的 Python 目录是什么样子的。这张图片有点误导,因为它没有包括我所有的目录或文件夹。这是我的真实样子(见图 10-2 ):

img/468718_1_En_10_Fig2_HTML.jpg

图 10-2。

我的真实 Python 目录视图,显示文件和文件夹

如果你已经按照这本书的建议创建了文件,你的看起来会很相似,只是少了一两个文件。

让我们继续创建一个新目录,我们将使用osmkdir()方法将其命名为 new directory。将这段代码添加到您的WorkingWithDirectories.py文件中:

# Create a new directory or folder
os.mkdir("newDirectory")

现在,运行文件,这将创建一个名为newDirectory的新文件夹。如果你打开你的 Python 目录文件夹,你应该看到它被添加到列表中,类似于我的(见图 10-3 ):

img/468718_1_En_10_Fig3_HTML.jpg

图 10-3。

新创建的“新目录”文件夹

现在,下一部分很重要!在更改目录之前,我们现在要注释掉刚刚添加的代码。我们这样做,因为如果我们不这样做,我们将收到一个错误消息。为什么?因为 Python 不会创建一个已经存在的目录。既然我们刚刚创建了它,那么,你就明白了!

修改你的代码,使之与我的相匹配,然后运行程序。

注意

确保(" C:/Users/James/AppData/Local/Programs/Python/Python 36-32/new directory ")与您的目录匹配,而不是我的目录;您可以使用本节第一个示例中返回的值,我们在第一个示例中学习了如何使用 os.getcwd()。否则,您会得到一个错误。此外,确保将目录路径中的改为/,否则也会收到错误。

下面是代码:

# Import the module os
# This is used to work with operating system information
import os

# Use the getcwd() method of the os module
# To see what directory we are in
os.getcwd()

# Create a new directory or folder
# We commented this out because we created the directory earlier
# If we don't, Python will try to create it again
# Causing an error

# os.mkdir("newDirectory")

# Using the chdir() method to change directories
os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32/newDirectory")

print(os.getcwd())

警告!如果您收到错误消息,原因很可能是您试图更改的目录不正确。如果您编写的代码与我的代码完全匹配,情况肯定是这样。记住,我们的目录是不同的,所以你必须插入你的目录。例如:

os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32/newDirectory")

这是我如何改变我的目录;你的可能更像:

os.chdir("C:/Users/YourName/Programs/Python/Python36-32/newDirectory")

它应该与本节第一个例子中的os.getcwd()例子返回的内容相匹配,再加上/newDirectory.

另外,记得把你的反斜杠改成正斜杠。例如,我的原始目录是:

C:\Users\James\AppData\Local\Programs\Python\Python36-32

但是当我们用代码写的时候,应该是:

C:/Users/YourName/Programs/Python/Python36-32/

一旦您的代码被整理出来并运行它,您将会收到与此类似的输出:

c:\ Users \ James \ AppData \ Local \ Programs \ Python \ Python 36-32 \ new directory

显示您切换到的目录。只要最后一部分说\newDirectory,我们就知道代码工作了。

既然我们已经知道了如何创建一个新目录以及如何切换到一个不同的目录,那么让我们切换回原来的目录,这样我们就可以继续处理我们在本书中已经创建的代码。

要切换回来,我们只需再次使用 chdir()方法,这次将它指向我们的原始目录。记住,用你原来的目录代替我为自己写的目录:

# Using the chdir() method to change directories
print("Changing to the newDirectory folder: ")
os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32/newDirectory")

# Print out the current directory to verify it changed
print(os.getcwd())

# Switching back to the original directory
# Remember to use your own directory, not mine!
os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32")

# Verifying that we are back to the original directory
print("Back to the original directory: " )
print(os.getcwd())

这里,我们添加了几个print()函数来显示我们处于目录切换的哪个阶段。我们还添加了一个最终的目录更改,以返回到我们的原始目录。运行时,结果应该类似于:

Changing to the newDirectory folder:
C:\Users\James\AppData\Local\Programs\Python\Python36-32\newDirectory
Back to the original directory:
C:\Users\James\AppData\Local\Programs\Python\Python36-32

在我们结束关于创建目录和在目录之间来回切换的讨论之前,还有最后一件事。为了避免将来出现任何混淆,让我们继续删除 newDirectory 文件夹。我们只需打开 Python 文件夹,单击该文件夹并选择“删除”即可。然而,我们现在是程序员了,而且,正如众所周知的程序员所做的那样,我们应该使用代码来为我们做艰苦的工作!

要删除目录,只需将以下代码添加到文件中:

# Deleting the newDirectory directory
# Using the rmdir() method

os.rmdir('newDirectory')

一旦运行了这段代码,如果查看 Python 文件夹,就会发现newDirectory文件夹已经不存在了。注意,我们不需要使用 Python 的完整路径来查找目录。这是因为该文件夹存在于我们指示 Python 在其中进行搜索的当前根文件夹中(即C:\Users\James\AppData\Local\Programs\Python\Python36-32)。如果您要将文件夹更改为“newDirectory”,那么在使用 mkdir 和 chdir 时也是如此

奖励回合!

在这一章中,我们学习了很多关于使用文件和导航目录的知识,但是仍然有一些事情我们需要学习如何去做。我不想用太多的信息淹没你,所以我将使这个特殊的超级秘密奖金回合简短而甜蜜。

在上一节中我们学习了如何删除目录,但是删除文件呢?删除文件非常简单;我们所做的就是使用remove()方法,如下所示:

# import os
import os

# Remove a file use the remove() method
os.remove('test.txt')

这段代码将从当前的目录中删除文件test.txt。如果文件位于当前目录之外的目录,我们可以切换到该目录,然后使用 remove()或者我们可以只给 remove()方法提供文件路径和名称,如下所示:

# import os
import os

# Remove a file use the remove() method
# If the file existed in the newDirectory folder
os.remove('C:\Users\James\AppData\Local\Programs\Python\Python36-32\newDirectory\test.txt')

其中目录将等于文件所在的目录路径。

最后,有时您可能希望更改文件的名称。我们可以使用另一种方法:

# import os
import os

# Rename the file using the rename() method
# Rename requires two arguments
# The current filename and the new filename

os.rename('test.txt', 'newTest.txt')

这段代码将我们当前目录中的文件test.txt重命名为newTest.txt

FunWithFiles.py 代码

这是我们的FunWithFile.py文件中所有代码的编译副本。请随意更改这段代码并进行试验,经常运行它以查看更改的结果!

# This code is used to open a file
# However, since the file does not already exist
# Python instead creates it for us
newFile = open("CreatedFile.txt", 'w')

# This code is similar to a print() statement
# However, instead of writing text or output to a user's computer screen
# It writes it to a file instead
newFile.write("Look, we created a brand new file using Python code!\n")
newFile.write("Here is a second line of text!\n")

# The close() function closes the file we are working on and saves it
# It is important to always close a file when we are finished with it
# To ensure we do not make any additions or mess up the file in anyway
newFile.close()

# Open the file CreatedFile.txt
read_me_seymour = open("CreatedFile.txt", 'r')

print("THE ORIGINAL TEXT IN THE FILE")
print(read_me_seymour.readline())
print(read_me_seymour.readline())

# Closing the file
read_me_seymour.close()

# Opening the file again to write some text to it
addingToFile = open("CreatedFile.txt", 'a')

# Adding some text to the file in append mode
addingToFile.write("This is new text.")

# Closing the file
addingToFile.close()

# Opening the file yet again, to read it
# Now that we have appended a line

print("THE TEXT IN THE FILE AFTER WE APPEND")
appendedFile = open("CreatedFile.txt", 'r')

# This is another way we can print from a file
# Here we are using a for loop
# And using the keywords in and line to print each line

# In the text file

for line in appendedFile:
    print(line)

# Closing the file again
appendedFile.close()

WorkingWithDirectories.py

下面是来自WorkingWithDirectories.py文件的完整代码。请注意,有些代码被注释掉了,因为多次使用它会导致错误。这与我们何时创建和删除新目录特别相关,如果我们试图创建一个已经存在的目录,将会导致错误。

再次强调,请随意试验这段代码,最重要的是,从中获得乐趣。毕竟,破解代码——然后修复它——是我们成为真正强大的编码超级英雄的方法!

# Import the module os
# This is used to work with operating system information
import os

# Use the getcwd() method of the os module
# To see what directory we are in
os.getcwd()

# Create a new directory or folder
# We commented this out because we created the directory earlier
# If we don't, Python will try to create it again
# Causing an error

# os.mkdir("newDirectory")

# Using the chdir() method to change directories
print("Changing to the newDirectory folder: ")
os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32/newDirectory")

# Print out the current directory to verify it changed
print(os.getcwd())

# Switching back to the original directory
# Remember to use your own directory, not mine!
os.chdir("C:/Users/James/AppData/Local/Programs/Python/Python36-32")

# Verifying that we are back to the original directory
print("Back to the original directory: " )
print(os.getcwd())

# Deleting the newDirectory directory
# Using the rmdir() method

os.rmdir('newDirectory') 

在这一集里!

你在这次冒险中真的很勇敢,年轻的英雄!你学到的足以让聪明的伊诺布瑞恩嫉妒。顺便说一句,你应该看看那个家伙的额头——很大!

尽管你很聪明,很有天赋,但是对你所学的知识进行一点复习总是一个好主意。所以,事不宜迟——在恶魔偷走你的荣耀之前——以下是这一集的总结:

  • Python 能够处理许多文件类型,包括。py,。txt,。html,。c、CSV 和 JSON。

  • open()用于打开一个文件;如果不存在同名文件,也可以使用 open()创建文件。

  • 使用 open()的例子:open("CreatedFile.txt ",' w ')。

  • “w”参数用于以写模式打开文件。

  • “x”参数用于以创建/写入模式打开文件。

  • 那个。write 方法允许我们向文件中添加文本。

  • 使用的示例。write 方法:newFile.write("这里是一些文本。").

  • 当您使用完一个文件时,请务必使用 close()函数关闭它。

  • 使用 close()的示例:newFile.close()。

  • 参数“r”用于打开文件进行读取。

  • 那个。read()方法读取文件中的所有文本。

  • 使用的示例。read()方法:print(readMe.read())。

  • 我们使用 readline()来读取文件中的一行。

  • readline()的一个例子:print(readMe.readline())。

  • append 参数“a”应该用于写入现有文件。使用“w”将覆盖现有文件的内容。

  • 要使用目录,我们必须导入操作系统。

  • 我们使用 getcwd()来查看我们当前的目录。

  • 使用 getcwd()的示例:os.getcwd()。

  • 我们使用 mkdir()创建一个新目录。例如:os.mkdir("newDirectory ")。

  • 我们使用 chdir()来改变目录。例如:os.chdir("C:/Users/YourName/")。

  • 我们可以使用 rmdir()移除或删除一个目录。例如:os.rmdir("newDirectory ")。

  • 我们可以使用 os.remove()删除文件。比如:os.remove('test.txt ')。

  • 我们可以使用 os.rename()来重命名文件。比如:os.rename('test.txt ',' newTest.txt ')。

十一、Python 游戏

我们专门有一章讨论用 Python 创作视频游戏是非常合适的——毕竟,正是这种兴趣让我在小时候就开始编程。从那以后,事情有了很大进展;当时,PC 游戏是基于文本的,仅有的图像由质量很差的图形组成,或者更糟糕的是,由 ASCII 字符组成。

甚至连声音都非常基本:想想单音数字 boops、beep 和 borps。还有动画?嗯,它们在技术上是存在的——对于我那个时代的真正高科技电脑游戏的一个很好的例子,可以看看 YouTube 上的游戏视频,比如《卡门·圣地亚哥在哪里》和我最喜欢的《俄勒冈小径》。

去吧,我等着。笑完了?好,我们继续。

这并不是说没有质量更好的视频游戏。雅达利在这一点上已经存在了很长时间,任天堂娱乐系统(NES)、世嘉和 Commodore 都可以使用。我甚至拥有一台任天堂,对它的高科技 8 位图形和尖端的声音惊叹不已。

虽然这些游戏很棒——其中一些至今仍然存在,而且比我在 PS4 上运行的许多游戏都有趣——但这些主机游戏缺少我的 PC 游戏所具备的一项功能;我能够破解它们,更重要的是,在电脑上创建我自己的版本。

现在情况不同了。如果你愿意,你可以为主要的主机购买一个开发人员控制台,如果有合适的资源和技能,开始开发你自己的游戏。这些游戏是否会在任何游戏商店出现,谁也说不准,但关键是,从技术上讲,现在你可以创建主机游戏。

那时候,在我这个年纪,你不能。

视频游戏是学习计算机编程技能的好方法。给定一个足够复杂的视频游戏,你真的可以弯曲你的编码肌肉。你开始以你通常不会想到的方式使用代码,你真的需要在编写代码之前为游戏计划好代码——这一部分非常重要,尤其是如果你创建了一个背后有故事情节的游戏。

然而,对我来说,更重要的是电子游戏可以灌输给一个人的激情。我希望,如果这本书里没有任何东西真正激发你的想象力或者让你对编程感兴趣,那么创建你自己的游戏将会。

即使你没有创作游戏的欲望,而对安全、桌面应用、数据科学或使用 web 框架更感兴趣,我仍然鼓励你继续阅读本章。虽然不会涉及大量的深入编码,但我们确实涵盖了一些可以在游戏之外使用的概念,例如处理声音、图像甚至动画。

此外,每个英雄都需要尽可能多地了解他们的力量。我的意思是,他们说超人可以跳过高楼,但你多久能看到他这样做?

尽管如此,有一天可能会发生一些事情,他再也不能飞行了(也许他会失去他的飞行员执照),然后他将如何到达一座建筑物的顶部,以阻止那个有着巨大大脑的巨型猿在大都会市区举办一场非常酷但完全邪恶的屋顶派对?

游戏用 Python

诚然,当你想到视频游戏编程时,Python 不是第一个想到的语言。也就是说,它被用在一些大型游戏中——《战地》就是一个很好的例子,它在 PC 和游戏机上使用 Python。

如果你真的想成为一名游戏开发者,你会想尽可能多地学习 C++ 和 JAVA。这是目前大多数游戏使用的两种顶级语言。其他的,比如 C#(用 Python 扩展的)也在使用,但是实际上,你应该关注 C++,特别是如果你想追求主机和 PC 游戏。

如果你计划编写基于网络的游戏,那么你需要 HTML5、CSS3、JavaScript 和 SQL(一种数据库语言)。

当然,你可以用多种语言来开发游戏,但是这里列出的是最重要的语言。

也就是说,如果你想学习核心概念,甚至创建自己的游戏——无论是为了娱乐,与朋友分享,还是作为你投资组合的一部分,Python 都是一个不错的选择。Python 比 C++ 容易学得多,如果你已经学了这么多,你已经很好地掌握了编码基础。

Python 还有非常方便的pygame模块,我们在书的前面安装了它,它实际上是一堆不同模块的集合,让你可以用 Python 创建自己的游戏和动画。

因为这是一本关于 Python 的书,我们将关注如何用 Python 创建游戏;但是我不希望你忽视这样一个事实,一旦你掌握了 Python,你应该增加其他语言到你的技能中。

可以用 Python 编码的游戏类型

你可以用 Python 创作的游戏类型没有限制——至少在理论上是这样。可以做角色扮演游戏(RPG)、第一人称射击游戏(FPS)、平台、益智游戏等等。这些游戏可以是基于文本的,混合了简单的图形、声音和文本,动画,2D 侧滚动条(想想像 NES 上的魂斗罗这样的游戏),甚至 3D 游戏。

如果你想拓展到制作 3D 游戏,你需要学习一些额外的技术,比如 Panda3D ( www.panda3d.org/ )。我们在这里不会深入到游戏开发中,但是要知道这个选项是存在的。

虽然 Python 可以帮助你制作出优秀的游戏,但真正的资源密集型游戏——需要大量内存和处理能力的游戏——最好用 C++ 来制作,这样你就可以更好地使用处理和图形硬件。

要真正了解你可以用 Python 开发什么类型的游戏——特别是你可以用本章将要介绍的pygame模块编写什么类型的程序——访问 Pygame 官方网站的项目库,浏览那里托管的大量游戏: www.pygame.org/tags/all

可以按类型、使用的库等查看 Python 程序员开发的游戏。这是一个获得一些想法和灵感的好地方,也是玩一些游戏和享受乐趣的好地方!

游戏简介

如果你一直在阅读本书,我们已经安装了pygame模块,但是不要担心——如果你跳过了这一部分或者想再次学习如何安装,我们将再次安装它。

然而,首先我们应该谈谈 Pygame 的历史以及它到底是什么。

虽然我们将pygame称为一个模块,但实际上,它是一组专门为视频游戏开发而创建的模块。由 Pete Shinners 开发,第一个版本发布于 2000 年 10 月。这些模块是使用 Python、C 和 Assembly 混合制作的。

除了 PC 上的游戏,Pygame 还可以用于使用一个称为 PGS4A 的子集为 Android 设备开发游戏;您可以通过访问 http://pygame.renpy.org/ 来了解更多关于使用这个特定子集为移动开发编程游戏的信息。

安装 Pygame

如前所述,我们已经安装了pygame模块。然而,为了清楚起见,这里是如何再次安装它,以防你不想把几章翻到第七章的。

要安装一个模块——特别是pygame——打开命令或 CMD 窗口,在命令提示符下输入以下内容:

python -m pip install Pygame

如果您还没有安装 pygame,您将在 CMD 窗口中看到软件包的下载和安装过程。该消息将类似于图 11-1 :

img/468718_1_En_11_Fig1_HTML.jpg

图 11-1。

安装 pygame

就是这么简单!

为游戏设置 Pygame 的基本框架

我们首先需要一个结构来创建我们的 Pygames。为此,我们可以使用一个最基本的引擎——因为没有更好的词,它看起来像这样:

import pygame
from pygame.locals import *
import sys

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600))

# Create a loop that will keep the game running
# Until the user decides to quit

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

这是一个使用pygame模块的游戏的非常简单的版本。虽然这段代码中没有技术上可玩的游戏,但它确实为我们创建了一个构建游戏的系统。代码的工作方式如下。

在导入我们需要的模块——pygamesys—之后,我们还要导入pygame中包含的所有额外模块。导入pygame应该足够了,但是有时——取决于您的系统——与pygame捆绑在一起的所有模块都无法加载,所以我们使用

from pygame.locals import *

确保我们进口的所有东西都是以防万一。

既然我们的模块已经加载,我们需要初始化所有的pygame模块。我们使用代码:pygame.init()这样做。

到目前为止,在我们的程序中,我们已经使用 IDLE 运行了代码,并在 Python Shell 中显示了结果。然而,当我们使用 Pygame 编写游戏时,由于我们处理的是图形,我们需要创建一个实际的屏幕来显示我们的程序。我们使用。display.set_mode()创建一个窗口或屏幕。这行:screen = py game . display . set _ mode((800,600))

创建宽度和高度为 800 x 600 像素的屏幕或窗口。我们稍后将在这个屏幕上绘制我们的图像、图形和文本。

这段代码的最后一部分——也是你需要为所有游戏创建的部分——被称为游戏循环。这个结构的目的非常简单:以鼠标点击和键盘/按键的形式接收用户的输入,这被称为事件

当我们创建一个交互式游戏时,我们需要一种方式让用户告诉游戏他们已经玩完了并退出。游戏循环也服务于这个目的。

while True开头的while循环开始游戏循环。然后程序等待用户采取行动——创建一个事件。现在,我们所有的游戏设置都是为了寻找一个QUIT事件。

一个QUIT事件意味着用户已经使用窗口右上角的红色 X 关闭了窗口。一旦发生这种情况,我们再次使用所有 Pygames 都必须具备的两个重要功能:pygame.quit()sys.exit()。这两个事件分别结束 Pygame 和退出游戏。你必须两者兼得;如果没有,你的窗户将冻结或挂起。

如果你现在运行这个程序,会弹出一个黑色背景的窗口。不会有别的事情发生。当你点击红色的 X 时,窗口会关闭,程序会结束。

加入我们的游戏框架

现在我们的 Pygame 游戏框架已经就位,如果我们想增加一点趣味,我们可以给它添加一点活力。毕竟我们是超级英雄,没有一点点天赋的英雄算什么?

首先,我们创建一个名为pygameExample.py的新文件。向其中添加以下代码:

import pygame
from pygame.locals import *
import sys

# Creating a tuple to hold the RGB (Red, Green Blue) values
# So that we can paint our screen blue later
colorBLUE = (0, 0, 255)

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600), 0, 32)

# Set a caption to our window
pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

# Draw a blue background onto our screen/window
screen.fill(colorBLUE)

# Draw the now blue window to the screen
pygame.display.update()

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

这段代码类似于我之前展示的例子。我确实在代码中添加了几行代码,目的是美化窗口,让它看起来更好一些。

我添加的第一段代码是:

colorBLUE = (0, 0, 255)

如注释所示,这是一个元组,它的值代表 RGB(红、绿、蓝)值,我们稍后将使用这些值来给屏幕着色。我们必须将这些值作为元组值传递给我们的screen对象/变量,因为这是它接受的数据类型。

RGB 值背后的理论是这样的:使用红色、绿色和蓝色的组合,你可以使任何颜色对人眼可见。在我们的例子中,0的第一个值意味着我们的颜色中没有红色。第二个值0意味着我们的颜色中没有绿色。最后,第三个值255是我们可以添加的最大蓝色量。举例来说,如果我们使用(0,0,0)来代替,我们最终会得到黑色,这是一种没有任何颜色的颜色。另一方面,(255,255,255)等同于白色,因为白色是所有颜色的组合。

接下来,我们想给我们创建的窗口添加一个标题,我们通过使用。display.set_caption(),如这行:

pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

这段代码将创建一个标题,位于窗口的顶部,如图 11-2 所示:

img/468718_1_En_11_Fig2_HTML.jpg

图 11-2。

窗口标题的示例

之后,我们要用蓝色填充背景/屏幕。为此,我们使用了.fill():

screen.fill(colorBLUE)

请注意,这实际上并没有向窗口添加任何内容。在实际绘制蓝色背景之前,我们需要使用.display.update()更新显示:

pygame.display.update()

现在,当我们保存并运行我们的程序时,会弹出一个蓝屏,与之前的黑屏不同,并带有我们程序的标题。去试试吧;只要记得点击红色的 X 退出程序。

在 Pygame 中添加图像和精灵

现在我们知道了如何格式化我们的游戏窗口和建立一个基本的游戏循环,接下来我们要做的是学习如何处理图像。毕竟,使用pygame模块的全部目的是为了让我们可以创建视频游戏,对吗?

当我们讨论二维或 2D 视频游戏中的图像时,我们称之为精灵。这是一个关于精灵是什么的简单的观点,但是对于我们的目的来说,它会工作得很好。

电子游戏中的精灵通常是指代表玩家的角色、敌人或图像。精灵也是游戏中的物体,比如子弹、树、石头等等。

这些精灵可以是静态的——不动的——也可以是动态的。在这一节中,我们将简单地讨论一个静态精灵。你可能已经注意到我们的窗口说明/标题是:超级助手:斗牛犬索菲;这不是意外!

很多超级英雄都有动物伙伴。由于害怕被起诉,害怕失去我的巨额财富和收藏的老式助力车,我不敢说出任何一辆,但相信我,有很多这样的车。

你和我有什么不同?难道我们不应该有一个伙伴动物吗?我的刚好是一只叫苏菲的牛头犬,它的超能力是打嗝,睡觉,咬我的脚趾,还打很响的呼噜。

对于这部分代码,我将在游戏窗口中添加一张斗牛犬索菲的图片。如果你愿意,你可以跟着去。更好的是,如果你有一张你的动物的图片——或者任何你想成为你伙伴的动物——把图片保存在你的pygameExample.py文件所在的文件夹中;如果不这样做,你的程序就找不到它。

最后一点:确保你使用的是你的文件名,而不是我在程序中输入的文件名。比如我正在使用的图像命名为,“SophieTheBullDog.jpg”;你的名字可能不同。

将下面的代码添加到您的pygameExample.py文件中,就在您使用screen.fill的部分下面,在您使用pygame.display.update()之前:

sidekick = pygame.Rect(100,100, 200, 200)
sophie = pygame.image.load('SophieTheBullDog.jpg')
thumbnail_sophie = pygame.transform.scale(sophie, (200,200))
screen.blit(thumbnail_sophie, sidekick)

在解释完这一部分之后,我将发布完整的更新代码,这样您就可以将您的文件与我的文件进行比较。

我们要做的第一件事是创建另一个表面,在上面绘制我们的图像。我们在下面的代码行中实现了这一点:sidekick = pygame.Rect(100,100, 200, 200)

这一行代码创建了一个矩形窗口,它位于屏幕的 100 x 100 的 XY 坐标处,大小为 200 x 200 像素(高和宽)。

XY 坐标与对象出现在屏幕上的位置相关。我们在 Pygame 中创建的表面由像素组成,每个像素位于一个与其 XY 位置相关的网格上。窗口的左上角位于 XY 位置(0,0)。因此,当我们在位置(100,100)绘制矩形时,我们实际上是在说,它将位于第 100 个像素处和第 100 个像素处。

如果那一点很混乱,不用太担心;几分钟后你运行这个程序就会明白了。

下一行代码:

sophie = pygame.image.load('SophieTheBullDog.jpg')

将名为'SophieTheBullDog.jpg'的图像存储在变量sophie中。同样,您的图像名称将与我的不同,所以只需用您的名称替换我的图像名称。

由于我的'SophieTheBullDog.jpg'图像相当大——它的尺寸为 1400 x 1400——它太大了,以目前的尺寸无法在游戏窗口中显示——更不用说在我们为它创建的矩形表面上了。因此,我们需要缩小它的尺寸。

我们使用.transform.scale()来实现这一点,它通过将图像缩放到我们给定的大小来转换图像。

我们的产品线:

thumbnail_sophie = pygame.transform.scale(sophie, (200,200))

将图像缩小到 200 x 200 像素,大小与我们创建的sidekick对象矩形曲面完全相同;如果我们将它放大到比表面更大,我们将无法看到整个图像,因此请始终确保图像的尺寸或大小与您创建的用于显示图像的表面相匹配。

最后,最后一步将是实际绘制——或者blit,记住——调整大小的图像到我们创建的sidekick矩形表面。为此,我们键入:

screen.blit(thumbnail_sophie, sidekick)

括号()中的第一个参数是我们要blit的对象的名称;第二个参数是我们想要将图像放到的对象(包括它的位置)。

下面是最终代码的样子;修改你的代码,使它看起来像我的,确保把你的图片的名字改成你的图片的名字。还要确保将您的图像移动到与您的pygameExample.py文件相同的文件夹中,否则,同样无法工作:

import pygame
from pygame.locals import *
import sys

# Creating a tuple to hold the RGB (Red, Green Blue) values
# So that we can paint our screen blue later
colorBLUE = (0, 0, 255)

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600), 0, 32)

# Set a caption to our window
pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

# Draw a blue background onto our screen/window
screen.fill(colorBLUE)

# Create a surface to hold our image
sidekick = pygame.Rect(100,100, 200, 200)

# create an object to load our image into
sophie = pygame.image.load('SophieTheBullDog.jpg')

# Resize our image so it fits the surface we are going to
# blit or paint our image onto
thumbnail_sophie = pygame.transform.scale(sophie, (200,200))

# blit or paint the image to the screen
screen.blit(thumbnail_sophie, sidekick)

# Draw the now blue window to the screen
pygame.display.update()

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

保存代码并运行它。您的结果看起来将与我的不同,因为我使用的图像与您的不同,但您的结果应该类似于图 11-3 。

img/468718_1_En_11_Fig3_HTML.jpg

图 11-3。

向 Pygame 游戏窗口添加图像

在我们继续之前,请确保更改 sidekick 矩形表面的 XY 坐标,以便您可以看到 XY 坐标是如何工作的。例如,将该行改为:

sidekick = pygame.Rect(100,100, 200, 200)

sidekick = pygame.Rect(200,200, 200, 200)

等等。

向我们的 Pygame 游戏窗口添加文本

在我们的游戏中加入图像很棒,但是文本呢?我们也可以添加文本,这正是我们将在本节中做的。

在你的 Pygame 游戏窗口中添加文本和添加图片的过程类似;也就是说,你必须首先创建一个表面来绘制它们。然后,在你向它发送文本之前,你指定这个表面将出现在窗口的什么地方。

将下面的代码添加到pygameExample.py文件中,就在我们使用screen.fill(colorBLUE)代码的地方的下面:

# Prepare our font for text
myFont = pygame.font.SysFont('None', 40)

# Create a text object
firstText = myFont.render("Sophie The Bulldog", True, colorRED, colorBLUE)

# Create the surface to write our text onto and its position
firstTextRect = firstText.get_rect()
firstTextRect.left = 100
firstTextRect.top = 75

# blit our text to the window
screen.blit(firstText, firstTextRect)

我们还将定义一种新的颜色colorRED,用于我们的文本。将此文本放在您定义colorBLUE的地方:

colorRED = (255, 0, 0)

在我解释完这些最新版本后,我将显示当前编辑过的代码供您比较。

首先,我们创建了一个对象来存储我们的字体,一旦我们创建了文本对象,它将被应用到我们的文本对象中。我们在生产线上这样做:

myFont = pygame.font.SysFont('None', 40)

pygame.font.SysFont()的自变量是'None'40。第一个参数告诉 Pygame 使用什么字体。我们可以使用一个字体名称,比如'Arial',但是我选择了'None',允许 Pygame 使用默认的系统字体。参数40告诉 Pygame 在呈现(或绘制)我们的文本时使用什么大小的字体。

接下来,我们实际创建我们的文本对象:

 firstText = myFont.render("Sophie The Bulldog", True, colorRED, colorBLUE)

在本例中,myFont.render()有两个参数。第一个是我们实际想要打印到屏幕上的文本。第二个参数—True—告诉 Pygame 您是否希望您的文本抗锯齿。这意味着你是否希望它是平滑的;True意为顺利,False意为不顺利。

第三个参数(colorRED)是我们希望文本呈现的颜色,它基于我们在程序开始时声明的颜色元组。第四个也是最后一个参数是我们的文本背景应该是什么颜色。我把它设置为colorBLUE,这样它就可以和我们窗口的颜色相匹配。

接下来,我们定义我们的表面,它是一个矩形,我们将在其上打印我们的文本对象。然后我们设置表面的位置,类似于我们决定图像出现的位置。

告诉 Pygame 在距离屏幕左侧 100 像素处绘制矩形表面。firstTextRect.top = 75告诉 Pygame 从屏幕顶部向下 75 像素绘制矩形表面。

重要的是,我们要记住我们之前画的图像与我们放置文本的位置之间的关系。

例如,您可能还记得,我们的图像被放置在下方 100 像素和左侧 100 像素处。

通过将文本表面设置为距离左侧 100 像素,我们也确保了它与我们的图像正确对齐。我们将文本的顶部设置为 75,这样它就位于图像的正上方。

最后,我们使用screen.blit(firstText, firstTextRect)将文本绘制到屏幕上。

这是我的图像在应用新代码后的样子——你的看起来应该类似于图 11-4 。

img/468718_1_En_11_Fig4_HTML.jpg

图 11-4。

向我们的 Pygame 游戏窗口添加文本

这是添加我们的图像和文本后的代码的当前版本。确保您的代码与我的代码匹配:

import pygame
from pygame.locals import *
import sys

# Creating a tuple to hold the RGB (Red, Green Blue) values
# So that we can paint our screen blue later
# And our text red
colorBLUE = (0, 0, 255)
colorRED = (255, 0, 0)

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600), 0, 32)

# Set a caption to our window
pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

# Draw a blue background onto our screen/window

screen.fill(colorBLUE)

# Prepare our font for text
myFont = pygame.font.SysFont('None', 40)

# Create a text object
firstText = myFont.render("Sophie The Bulldog", True, colorRED, colorBLUE)

# Create the surface to write our text onto and its position
firstTextRect = firstText.get_rect()
firstTextRect.left = 100
firstTextRect.top = 75

# blit our text to the window
screen.blit(firstText, firstTextRect)

# Create a surface to hold our image
sidekick = pygame.Rect(100,100, 200, 200)

# create an object to load our image into
sophie = pygame.image.load('SophieTheBullDog.jpg')

# Resize our image so it fits the surface we are going to
# blit or paint our image onto
thumbnail_sophie = pygame.transform.scale(sophie, (200,200))

# blit or paint the image to the screen
screen.blit(thumbnail_sophie, sidekick)

# Draw the now blue window to the screen
pygame.display.update()

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit

event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

在 Pygame 中绘制形状

在你的 Pygame 游戏中插入图像和精灵是添加场景、人物和物品的好方法,但是当涉及到图形时,它不是你唯一的选择,也不总是你最好的选择。您还可以使用一些相当简单的代码来绘制形状。

让我们从给我们的程序增加一些颜色开始。在我们定义先前颜色的位置下面,添加以下代码:

colorPINK = (255,200,200)
colorGREEN = (0,255,0)
colorBLACK = (0,0,0)
colorWHITE = (255,255,255)
colorYELLOW = (255,255,0)

接下来,我们将画出我们的第一批图形。我们将画三个圆——每个都以独特的方式与众不同。将以下代码添加到您的文件中,就在pygame.display.update()行之前:

# Drawing a circle

pygame.draw.circle(screen, colorRED, (330, 475), 15, 1)
pygame.draw.circle(screen, colorYELLOW, (375, 475), 15, 15)
pygame.draw.circle(screen, colorPINK, (420, 475), 20, 10)

.draw.circle方法有几个参数。第一个是我们想在什么表面上画圆;在本例中,我们将它绘制在screen上,这是我们之前为保存程序的表面对象而创建的变量的名称。

下一个参数是颜色,我们用colorRed定义了颜色。接下来,我们告诉 Python 我们希望圆位于哪个像素或 XY 坐标——在本例中,是圆心。

最后两个参数决定了我们的圆的半径(在这个例子中是 ??)和线条的粗细。

这里要注意的有趣的事情是,如果我们只在创建第一个圆后运行程序,我们会看到一个没有填充颜色的圆。这是因为我们将最后一个参数——线条粗细——设置为1。如果我们想用颜色填满我们的圆,我们可以让线条的粗细等于半径。

作为比较,我们展示了一个例子,在我们画的第二个圆中,它的半径是15,厚度也是15

最后,我们画第三个圆,这一次,我们将圆的厚度设为半径的一半,这样我们就可以看到会发生什么。作为猜测,我会说我们最后的圆圈看起来像一个油炸圈饼。让我们看看我是不是对的。保存程序并运行它。您应该会看到类似于图 11-5 的结果:

img/468718_1_En_11_Fig5_HTML.jpg

图 11-5。

在我们的 Pygame 游戏窗口上绘制图形

你的结果应该和我的差不多。

这里有一些你可以画的不同形状的例子(暂时不要把它们添加到你的文件中):

  • Circles: pygame.draw.lines(表面、颜色、(x,y)、半径、厚度)

示例:pygame.draw.circle(screen,colorYELLOW,(375,475),15,15)

  • Rectangle: pygame.draw.rect(表面,颜色,(x,y,宽度,高度),厚度)

示例:pygame.draw.rect(screen,colorYELLOW,(455,470,20,20),4)

  • Line: pygame.draw.line(表面,颜色,(X,Y 坐标为线的起点),(X,Y 坐标为线的终点),粗细)

示例:pygame.draw.line(screen,colorRED,(300,500),(500,500),1)

继续将以下代码行添加到您的文件中,就在我们放置代码以创建我们的圆的位置的下方:

pygame.draw.rect(screen, colorYELLOW, (455, 470, 20, 20), 4)
pygame.draw.line(screen, colorRED, (300, 500), (500,500),1)
pygame.draw.line(screen, colorYELLOW, (300, 515), (500,515),1)
pygame.draw.line(screen, colorRED, (300, 530), (500,530),1)

如果您运行这段代码,您的结果将类似于图 11-6 :

img/468718_1_En_11_Fig6_HTML.jpg

图 11-6

给我们的 Pygame 游戏窗口添加一些线条

添加更多事件

如果一个游戏不回应用户,那它有什么用?此外,什么样的程序只允许用户通过点击屏幕右上角的红色“X”来退出——这不是很直观,不是吗?

Pygame 程序能够对大量事件做出反应。这些事件可以是从点击鼠标、滚动滚轮、按下键盘上的箭头,或者按下标准键盘周期上的任何键,等等。

在我们离开我们的pygameExample.py文件之前,让我们再给程序添加几个事件,以便我们对事件如何操作有一个更好的感觉。

如果您一直在跟进,您的pygameExample.py代码应该与下面的代码相匹配;如果没有,花点时间确保它有:

import pygame
from pygame.locals import *
import sys
import random

# Creating a tuple to hold the RGB (Red, Green Blue) values
# So that we can paint our screen blue later
# And our text red
colorBLUE = (0, 0, 255)
colorRED = (255, 0, 0)
colorPINK = (255,200,200)
colorGREEN = (0,255,0)
colorBLACK = (0,0,0)
colorWHITE = (255,255,255)
colorYELLOW = (255,255,0)

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600), 0, 32)

# Set a caption to our window
pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

# Draw a blue background onto our screen/window
screen.fill(colorBLUE)

# Prepare our font for text
myFont = pygame.font.SysFont('None', 40)

# Create a text object
firstText = myFont.render("Sophie The Bulldog", True, colorRED, colorBLUE)

# Create the surface to write our text onto and its position

firstTextRect = firstText.get_rect()
firstTextRect.left = 100
firstTextRect.top = 75

# blit our text to the window
screen.blit(firstText, firstTextRect)

# Create a surface to hold our image
sidekick = pygame.Rect(100,100, 200, 200)

# create an object to load our image into
sophie = pygame.image.load('SophieTheBullDog.jpg')

# Resize our image so it fits the surface we are going to
# blit or paint our image onto
thumbnail_sophie = pygame.transform.scale(sophie, (200,200))

# blit or paint the image to the screen
screen.blit(thumbnail_sophie, sidekick)

# Drawing shapes

pygame.draw.circle(screen, colorRED, (330, 475), 15, 1)
pygame.draw.circle(screen, colorYELLOW, (375, 475), 15, 15)
pygame.draw.circle(screen, colorPINK, (420, 475), 20, 10)
pygame.draw.rect(screen, colorYELLOW, (455, 470, 20, 20), 4)
pygame.draw.line(screen, colorRED, (300, 500), (500,500),1)
pygame.draw.line(screen, colorYELLOW, (300, 515), (500,515),1)
pygame.draw.line(screen, colorRED, (300, 530), (500,530),1)

# Draw the now blue window to the screen
pygame.display.update()

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

我们将要添加事件的代码部分是我们的游戏循环,为了提醒您,这部分代码是:

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

对于游戏循环来说,这是非常简单的。如上所述,它只有一个事件。我们要做的第一件事是为用户添加另一种退出应用的方式。为此,我们将使用两种方法。首先,如果用户按下键盘上的“q ”,应用将会关闭。第二,如果用户按下 ESC 键,游戏也会关闭。一旦我们的代码被更新,用户将有三种方式退出我们的应用。

修改代码的游戏循环部分,使其与下面的代码相匹配。注意:非常注意正确的缩进:

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()

保存代码并多次运行您的程序。确保在重新运行程序时按下'q',点击红色的'X',并按下ESC键,以确保每个退出选项都有效。

注意,在我们的新代码中,我们有两个新的事件类型。第一个是pygame.KEYDOWN,当我们等待——或倾听——用户按下键盘上的按键时使用。

缩进在our pygame.KEYDOWN下面的事件类型是event.key,它定义了程序正在监听的确切的键。键盘上的大多数字母和数字是通过键入pygame.K_然后是字母或数字来定义的。

例如,要监听一个'a',您可以使用:

if event.type == pygame.KEYDOWN:
       if event.key == pygame.K_a:
             do something...

您可以通过访问 www.pygame.org/docs/ref/key.html 查看键盘常量的完整列表。此外,这里列出了一些您可以监听的更常用的键盘常量:

  • 向上箭头:K_UP

  • 向下箭头:K_DOWN

  • 右箭头:K_RIGHT

  • 左箭头:K_LEFT

  • 空格键:K_SPACE

  • 输入或返回:K_RETURN

  • 数字:K_0,K_1,K_2 等。

  • 字母:K_a,K_b,K_c,K_d 等。

在我们进入下一节之前,让我们向我们的pygameExample.py文件添加一个东西。让我们来听另一个事件——键盘字符“b”。当用户按下那个按钮时,程序会在屏幕上打印出一些文本。

为了实现这一点,让我们将以下内容添加到我们的游戏循环中,就在最后一个 if 块的下面:

if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_b:
                barkText = myFont.render("Bark!", True, colorRED, colorBLUE)
                barkTextRect = barkText.get_rect()
                barkTextRect.left = 300
                barkTextRect.top = 175
                screen.blit(barkText, barkTextRect)
                pygame.display.update()

到目前为止,您应该对这段代码的作用有了很好的理解。如果没有,那也没关系,我们会一步一步来。

首先,我们监听一个KEYDOWN事件类型——也就是说,有人按下了键盘上的一个键。接下来,我们告诉 Pygame 我们在听什么调:

if event.key == pygame.K_b:

这一行表示我们正在寻找被按下的'b'键。请务必注意KEYDOWN事件和KEYUP事件之间的区别。如上所述,当用户按下键盘上的给定键时,会发生一个KEYDOWN事件;当他们释放该键时,就会发生一个KEYUP事件。如果没有监听到KEYUP事件,那么一旦用户释放该键,什么也不会发生。

接下来,我们定义如果用户按下'b'键会发生什么。首先,创建一个名为barkText的文本对象。我们为文本对象设置参数——文本应该说什么,是否消除锯齿,文本的颜色,以及文本背景的颜色。

接下来,在该行中:

barkTextRect = barkText.get_rect()

我们定义了文本将驻留的表面。从那里,我们使用以下方式指示表面的位置:

barkTextRect.left = 300
barkTextRect.top = 175

最后,我们将文本对象及其表面放到屏幕上,并更新显示以显示我们新创建的文本。

如果您保存并运行这段代码,您将得到类似于图 11-7 的结果,只要您在应用加载后按下'b'键:

img/468718_1_En_11_Fig7_HTML.jpg

图 11-7。

让“斗牛犬索菲”吠叫!

没错——斗牛犬索菲吠叫了!显然她不喜欢我们之前画的那些讨厌的圆形、矩形和线条!

由于我们的'b'按钮事件中的“吠叫”文本已经被放置在我们的游戏循环中,从技术上来说,每次你按下'b',文本都会重新加载到屏幕上。然而,你将看不到这种情况发生,因为替换的“树皮”会立即出现,并且是同样的大小、形状和颜色。

每当用户按下'b'键时,有许多方法可以让文本出现。最简单的方法之一就是使用幻觉——这无疑会让阴险的数学魔术师 ?? 引以为豪!

为了营造这种错觉,我们将添加另一个按键事件。键仍然是'b',但是我们将添加一个KEYUP事件,而不是KEYDOWN事件。

这下一部分代码背后的想法很简单:一旦用户释放'b'按钮,“吠!”会消失。

事实是,我们只是改变了“树皮”这个词的颜色与背景颜色完全相同,使它看起来好像消失了,而实际上,它只是隐藏在背景中。

当用户再次按下'b'时,颜色将再次变为红色并再次可见。每当用户按下'b'时,这个循环将继续,直到他们退出应用。

将这段代码添加到您定义最后一个KEYDOWN事件的地方,保存它,然后运行程序。一定要多次按下“b”键,直到你看厌了苏菲的叫声!

注意

确保正确缩进,以便第一个 if 语句与前一个 if 语句对齐。

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_b:
                barkText = myFont.render("Bark!", True, colorBLUE, colorBLUE)
                barkTextRect = barkText.get_rect()
                barkTextRect.left = 300
                barkTextRect.top = 175
                screen.blit(barkText, barkTextRect)
                pygame.display.update()

如果您的代码不起作用,请花时间确保它与下面的代码匹配。以下是我们所有最新版本的pygameExample.py的完整代码:

import pygame
from pygame.locals import *
import sys
import random

# Creating a tuple to hold the RGB (Red, Green Blue) values
# So that we can paint our screen blue later
# And our text red
colorBLUE = (0, 0, 255)
colorRED = (255, 0, 0)
colorPINK = (255,200,200)
colorGREEN = (0,255,0)
colorBLACK = (0,0,0)
colorWHITE = (255,255,255)
colorYELLOW = (255,255,0)

# Initialize all of the Pygame modules so we can use them later on
pygame.init()

# Create the game screen and set it to 800 x 600 pixels
screen = pygame.display.set_mode((800, 600), 0, 32)

# Set a caption to our window
pygame.display.set_caption("Super Sidekick: Sophie the Bulldog!")

# Draw a blue background onto our screen/window
screen.fill(colorBLUE)

# Prepare our font for text
myFont = pygame.font.SysFont('None', 40)

# Create a text object
firstText = myFont.render("Sophie The Bulldog", True, colorRED, colorBLUE)

# Create the surface to write our text onto and its position

firstTextRect = firstText.get_rect()
firstTextRect.left = 100
firstTextRect.top = 75

# blit our text to the window
screen.blit(firstText, firstTextRect)

# Create a surface to hold our image
sidekick = pygame.Rect(100,100, 200, 200)

# create an object to load our image into
sophie = pygame.image.load('SophieTheBullDog.jpg')

# Resize our image so it fits the surface we are going to
# blit or paint our image onto
thumbnail_sophie = pygame.transform.scale(sophie, (200,200))

# blit or paint the image to the screen
screen.blit(thumbnail_sophie, sidekick)

# Drawing shapes

pygame.draw.circle(screen, colorRED, (330, 475), 15, 1)
pygame.draw.circle(screen, colorYELLOW, (375, 475), 15, 15)
pygame.draw.circle(screen, colorPINK, (420, 475), 20, 10)
pygame.draw.rect(screen, colorYELLOW, (455, 470, 20, 20), 4)
pygame.draw.line(screen, colorRED, (300, 500), (500,500),1)
pygame.draw.line(screen, colorYELLOW, (300, 515), (500,515),1)
pygame.draw.line(screen, colorRED, (300, 530), (500,530),1)

# Draw the now blue window to the screen
pygame.display.update()

# Create a variable to hold the value of whether
# The game should end or not
running = True

# Create a loop that will keep the game running
# Until the user decides to quit
# When they do, it will change the value of running
# To False, ending the game

while True:
# Get feedback from the player in the form of events
    for event in pygame.event.get():
        # If the player clicks the red 'x', it is considered a quit event
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_b:
                barkText = myFont.render("Bark!", True, colorRED, colorBLUE)
                barkTextRect = barkText.get_rect()
                barkTextRect.left = 300
                barkTextRect.top = 175
                screen.blit(barkText, barkTextRect)
                pygame.display.update()
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_b:
                barkText = myFont.render("Bark!", True, colorBLUE, colorBLUE)
                barkTextRect = barkText.get_rect()
                barkTextRect.left = 300
                barkTextRect.top = 175
                screen.blit(barkText, barkTextRect)
                pygame.display.update()

在这一集中

哇,多么激动人心的一章啊!如果你通过了这一章,只是因为头轻轻地撞在桌子上而有轻微的擦伤和瘀伤,干得好!本章涵盖的主题可能是最难掌握的;如果没有别的,它们和类和对象一样复杂,可能是你用 Python 思考过的最具挑战性的东西。

干得好!

但是现在还不要固步自封。下一章继续我们对 Pygame 的讨论,并深入到创建你自己的游戏的两个更困难——但强大且有益的方面:动画和碰撞检测。如果你想成为一名游戏开发者或者想要一个编程的挑战,你肯定不想跳过下一章!

因为这一章和下一章放在一起,而且是如此广泛的主题,我们将跳过通常在每一章结束时所做的总结;在要点中总结重要的谈话要点并不能恰当地表达主题。

相反,练习你在这一章学到的技能和你将在下一章学到的技能,并根据你的需要经常重读它们。

而且一如既往的实验,实验。

这就是游戏的名字!

十二、动画游戏

我看你回来是为了更多的惩罚——真有你的!如果我自己这么说的话,最后一章相当令人兴奋。你不仅学到了一些核心的游戏开发理论和实践,还实际编写了一些代码!

最重要的是,你要见见我的斗牛犬索菲。当她睡觉的时候,她是一只好狗,而且她是一个极好的宠物伙伴。我的意思是,当然,她倾向于睡觉,通过所有的行动,但如果你需要有人吃所有的食物和打嗝很多,嗯,你不能要求一个更好的合作伙伴。

上一期,我们学习了在游戏中绘制图形和插入图像。我们还学习了游戏循环和创建事件以允许用户与我们的游戏互动。

这一轮,我们学到了游戏开发的两个更重要的方面。首先是动画,这意味着让物体在屏幕上移动。第二种被称为碰撞检测,这是当两个或更多的物体接触或当一个物体接触到你的游戏窗口的边界时发生的事情。

我不会用冗长的介绍来烦你——哦,你说太晚了?

让我们开始吧,自作聪明的家伙!

在 Pygame 中创建动画

在学习游戏设计的一些核心概念以及如何使用pygame模块在 Python 中创建我们自己的游戏方面,我们已经走了很长的路。到目前为止,我们已经学会了如何创建背景、添加图像或精灵、插入文本,以及监听——更重要的是,响应——按键之类的事件。

创建一个可视化的 2D 游戏的真正关键在于动画,这是我们将在下一节讨论的内容。和所有 Python 的东西一样,在我们的 Pygames 中有许多实现动画的方法,但是因为这是一本初学者的书,我们将只看最简单的方法。

我们的最后一个应用pygameExample.py,变成了一个相当大的文件。为了避免混乱和节省空间,让我们创建一个名为pygameAnimations.py.的全新文件

我们将回收一些来自pygameExample.py, so don't fret if some of the code looks a bit familiar. Remember: we always want to reuse our code whenever possible and appropriate.的代码,特别是一些颜色变量和模块导入/初始化部分。

我们将对游戏结构本身以及游戏循环做一点改变。由于处理动画可能有点复杂,我想让我们的文件简洁明了,以便更好地解释事情是如何工作的。除此之外,动画的结构往往不同于静态图像和文本。

将以下代码添加到您的pygameAnimation.py文件中,以设置框架:

# import our modules
import pygame
from pygame.locals import *
import sys
import random

# Initialize our pygame modules
pygame.init()

# Create tuples for our colors
colorWHITE = (255,255,255)
colorBLACK = (0,0,0)
colorRED = (255,0,0)

# Create our main game window - last time we named it screen
# Let's give it a different name this time
gameWindow = pygame.display.set_mode((800,600))

# Set the caption/title for our animation
pygame.display.set_caption('Box Animator 5000')

因为我们已经在之前的应用中编写了该代码的一个版本,所以没有必要再重复一遍。只需知道是基本代码设置了我们的屏幕,定义了我们在图像和文本上使用的颜色,并导入和初始化了我们的模块。我们还将窗口的标题改为“Box Animator 5000”

接下来,我们想再创建几个变量:

gameQuit = False

move_x = 300
move_y = 300

第一个变量gameQuit将存储我们的游戏循环检查的值,以查看程序是否应该结束。只要gameQuit不等于 True,游戏就会继续;一旦它的值改为True,游戏就结束了。

接下来的两个变量—move_xmove_y—用于设置我们将要绘制的矩形对象的初始位置。我们将这些值放在一个变量中,而不是直接在矩形的参数中定义它们,因为我们将在应用的后面更改对象的 XY 坐标值。

move_x代表对象的 X 位置,而move_y用于其 Y 位置。

接下来将是我们的动画游戏的游戏循环。我们添加了一些新的事件,我们将详细讨论这些事件。将以下内容添加到您的代码中:

# Game Loop
while not gameQuit:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameQuit = True
            pygame.quit()
            sys.exit()
        # If the player presses 'q', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        # If the player presses 'ESC', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
        # If arrow key left is pressed, move the object left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                move_x -= 10
        # If arrow key right is pressed, move the object right
            if event.key == pygame.K_RIGHT:
                move_x += 10
        # If arrow key up is pressed, move the object up
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                move_y -=10
        # If arrow key down is pressed, move the object down
            if event.key == pygame.K_DOWN:
                move_y +=10

这个游戏循环的大部分应该是熟悉的。我们有几个事件涵盖了用户退出的方式——他们可以按下ESC'q',或者点击红色的'X'

然后我们为LEFTRIGHTUPDOWN箭头创建按键事件。如果按下这些按钮中的任何一个,将会发生以下情况:

  • 如果按下左键,move_x 的值减少 10,将对象向左移动 10 个像素。

  • 如果按下右键,move_x 的值增加 10,将对象向右移动 10 个像素。

  • 如果按下向上键,move_y 的值将减少 10,将对象向上移动 10 个像素。

  • 如果按下向下键,move_y 的值增加 10,将对象向下移动 10 个像素。

既然我们的游戏循环和事件已经就绪,剩下的最后一件事就是创建我们的窗口,用颜色填充它,blit 我们的形状,并更新显示:

    # Fill the gameWindow with the color white
    gameWindow.fill(colorWHITE)

    # Blit a black rectangle object
    pygame.draw.rect(gameWindow, colorBLACK, [move_x,move_y,50,50])

    # Update our screen
    pygame.display.update()

这就是我们的第一个动画游戏!继续运行程序并测试它。确保按下每个箭头键,然后再运行几次,以测试我们的每个“退出”事件。

您的屏幕看起来应该类似于图 12-1 :

img/468718_1_En_12_Fig1_HTML.jpg

图 12-1。

测试退出事件

很酷吧。这种类型的动画逻辑可以应用于各种游戏。例如,您可以制作一个赛车游戏,其中一辆汽车必须在街道上移动,一个格斗游戏,其中角色在棋盘上移动,等等。

当然,现在我们的游戏很无聊,但是这里要学习的主要概念是在棋盘上移动一个物体。

尽管这段代码很简洁,但它确实缺少一些东西。你可能已经注意到了一件事,如果你向任何方向移动盒子太远,它会离开屏幕,最终消失。从技术上讲,只要你向相反的方向移动它,它就会回来,但是你可以看到这会给我们的游戏带来怎样的问题。

有几种方法可以解决这个问题,我们将在下一节讨论。然而现在,让我们为矩形增加一种移动方式——随机传送!说说超能力吧!

在其余事件的底部添加以下代码片段:

        # if 't' is pressed, randomly teleport the object
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_t:
                move_y = int(random.randint(1,600))
                move_x = int(random.randint(1,600))

敏锐的观察者可能已经注意到,我们在程序开始时导入了random;原因如下。我们想在用户按下't'时随机生成矩形对象的 XY 坐标。为了做到这一点,我们使用了random.randint(),就像前面的例子一样。我们为它提供了一系列的1600像素,以确保它永远不会完全从屏幕上消失。

现在,您的代码应该是这样的;如果没有,或者如果您的代码不起作用,请确保所有内容都匹配,并且您的缩进设置正确:

# import our modules
import pygame
from pygame.locals import *
import sys
import random

# Initialize our pygame modules
pygame.init()

# Create tuples for our colors
colorWHITE = (255,255,255)
colorBLACK = (0,0,0)
colorRED = (255,0,0)

# Create our main game window - last time we named it screen
# Let's give it a different name this time
gameWindow = pygame.display.set_mode((800,600))

# Set the caption/title for our animation
pygame.display.set_caption('Box Animator 5000')

gameQuit = False

move_x = 300
move_y = 300

# Game Loop
while not gameQuit:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameQuit = True
            pygame.qui()
            sys.exit()
        # If the player presses 'q', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        # If the player presses 'ESC', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
        # If arrow key left is pressed, move the object left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                move_x -= 10
        # If arrow key right is pressed, move the object right

            if event.key == pygame.K_RIGHT:
                move_x += 10
        # If arrow key up is pressed, move the object up
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                move_y -=10
        # If arrow key down is pressed, move the object down
            if event.key == pygame.K_DOWN:
                move_y +=10
        # if 't' is pressed, randomly teleport the object
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_t:
                move_y = int(random.randint(1,600))
                move_x = int(random.randint(1,600))

    # Fill the gameWindow with the color white
    gameWindow.fill(colorWHITE)

    # Blit a black rectangle object
    pygame.draw.rect(gameWindow, colorBLACK, [move_x,move_y,50,50])

    # Update our screen
    pygame.display.update()

运行代码和传送,直到你的大脑爆炸!

碰撞检测:从墙上反弹

当我们在游戏中创建更多的对象时,我们不可避免地会遇到处理对象相互接触时的行为问题。例如,如果我们有两个移动到窗口中心的动画矩形,在某个时候,它们的路径会相交。

我们可以忽略这种联系,在某些情况下,这可能是最好的选择。不过,更有可能的是,我们希望让我们的对象检测到这种碰撞,并以某种方式做出反应。

碰撞检测是一种编程艺术,让对象“意识到”它们何时与另一个对象发生碰撞,然后做出适当的反应。在某些情况下,我们可能希望我们的对象停止朝那个方向移动。在其他情况下,我们可能希望它们反弹几步,就好像它们遇到了一个强大的力场。

冲突也可能因为其他原因而发生。例如,你可能创造了一个角色必须通过的迷宫。如果我们不设置碰撞检测,角色可能会直接穿过我们的墙壁。门也是如此。

事实上,即使屏幕上没有墙或门,或任何其他物体,设置碰撞检测也是一个好主意。为什么呢?当我们制作矩形动画的时候,我们非常简短地提到了这个话题;我们创造的能够移动的物体可以——也将会——超越我们定义的屏幕边界。

虽然窗本身没有墙边界,但实际上它们有边界。在这些情况下,窗口的高度和宽度就是边界。例如,假设我们有一个 800 x 600 像素的窗口。我们可以沿着这个窗口的侧面、顶部和底部设置应用的边界,使我们的对象在越过边界时被它们弹开。

最后,我们可能需要注意的另一种碰撞形式是有意碰撞。想象一个游戏,你正在向敌人射击子弹。每当这些子弹击中目标——或者碰撞——我们都会希望它们做一些事情,比如造成伤害、得分或者引发某种反应。

用最基本的术语来说,每当两个或更多的物体有意或无意地相互接触时,就会发生碰撞。

碰撞检测:检测窗口边界

当我们创建 Pygame 应用时,我们需要记住窗口的边界。在大多数情况下,我们希望我们的对象保持在窗口或游戏屏幕的宽度和高度之内。有些情况下不会这样,但出于我们的目的,我们将专注于当我们想要确保我们的对象留在玩家的视野内时该做什么。

对于我们的下一部分代码,我们将检查以确保我们的矩形对象没有超出我们的窗口的宽度或高度。要做到这一点,我们必须检查我们的矩形在棋盘上移动时的位置,并让我们的程序在矩形触及边界时做出响应。

为了实现这一点,我们将使用一系列的if语句,我们将把它们放在游戏循环和事件监听器下面,就在我们创建gameWindow.fill(colorWHITE)之前。

添加以下代码,确保正确缩进:

  # Check to see if we collide with the right screen end
        if move_x > 750:
            move_x -= 50
            pygame.display.set_caption('Right Collision')
        if move_x < 1:
            move_x += 50
        # Check to see if we collide with the left screen end
            pygame.display.set_caption('Left Collision')
        # Check to see if we collide with the bottom of the screen
        if move_y > 550:
            move_y -= 50
            pygame.display.set_caption('Bottom Collision')
        # Check to see if we collide with the top of the screen
        if move_y < 1:
            move_y += 50
            pygame.display.set_caption('Top Collision')

对于这么少的代码,它当然做了很多。让我们走一遍这些步骤。

我们的第一个if语句声明如果我们的矩形对象位于 750 像素或更大的空间,那么将我们的矩形对象向相反方向移动 50 像素,创建一个反弹效果。这是通过从move_x变量中减去50 (-=50来实现的,正如您所记得的,这个变量代表我们矩形对象的X坐标。

您可能已经注意到,我们没有让程序检查我们的对象是否位于高于800 X的像素坐标处。你可能会问,这是为什么?简单:我们必须时刻记住我们要检测碰撞的物体的大小。我们必须从最高坐标值中减去它的大小——在本例中为50。因此,如果我们的矩形是50像素,我们的屏幕是800像素宽,为了让我们的矩形接触边界而不超出边界,我们必须检查750或更大的X坐标。

我们代码的下一部分再次在X坐标上工作。这一次,我们正在检查与屏幕左侧的碰撞。这里我们要检查小于1的值(记住:屏幕左侧的边框位于X坐标0);同样,如果我们碰到这堵“墙”,矩形会向相反的方向反弹50像素。

我们也为Y坐标继续这个逻辑,检查我们窗口的顶部和底部碰撞。同样,如果检测到碰撞,我们的矩形将向相反的方向反弹50像素——这次相应地向上或向下。

最后,为了给程序增加一点趣味,如果检测到碰撞,每个if检查也会改变窗口的标题,提醒你碰撞发生在哪个方向——上、下、左或右。

这就是我们的第一个碰撞检测功能!

继续保存程序并测试它,确保碰到每面墙以确保程序正常工作。如果不匹配,请确保它与以下完整的程序代码匹配:

# import our modules
import pygame
from pygame.locals import *
import sys
import random

# Initialize our pygame modules
pygame.init()

# Create tuples for our colors
colorWHITE = (255,255,255)
colorBLACK = (0,0,0)
colorRED = (255,0,0)

# Create our main game window - last time we named it screen
# Let's give it a different name this time
gameWindow = pygame.display.set_mode((800,600))

# Set the caption/title for our animation
pygame.display.set_caption('Box Animator 5000')

gameQuit = False

move_x = 300
move_y = 300

# Game Loop
while not gameQuit:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameQuit = True
            pygame.qui()
            sys.exit()
        # If the player presses 'q', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        # If the player presses 'ESC', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
        # If arrow key left is pressed, move the object left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                move_x -= 10
        # If arrow key right is pressed, move the object right
            if event.key == pygame.K_RIGHT:
                move_x += 10
        # If arrow key up is pressed, move the object up
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                move_y -=10
        # If arrow key down is pressed, move the object down
            if event.key == pygame.K_DOWN:
                move_y +=10
        # if 't' is pressed, randomly teleport the object
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_t:
                move_y = int(random.randint(1,600))
                move_x = int(random.randint(1,600))

        # Check to see if we collide with the right screen end
        if move_x > 750:
            move_x -= 50
            pygame.display.set_caption('Right Collision')
        if move_x < 1:
            move_x += 50
        # Check to see if we collide with the left screen end
            pygame.display.set_caption('Left Collision')
        # Check to see if we collide with the bottom of the screen
        if move_y > 550:
            move_y -= 50
            pygame.display.set_caption('Bottom Collision')
        # Check to see if we collide with the top of the screen
        if move_y < 1:
            move_y += 50
            pygame.display.set_caption('Top Collision')

    # Fill the gameWindow with the color white
    gameWindow.fill(colorWHITE)

    # Blit a black rectangle object
    pygame.draw.rect(gameWindow, colorBLACK, [move_x,move_y,50,50])

    # Update our screen
    pygame.display.update()

碰撞两个物体

现在我们已经设置了边界检测,我们可以继续进行另一种重要的碰撞检测——检测两个对象何时发生碰撞。如前所述,您可能希望检查多个对象之间的碰撞有许多原因。除了查看两个角色是否接触或武器是否击中目标,碰撞检测对于确定物体在感知空间中的位置也很有用。

例如,如果你有一个游戏,其中一个角色必须跳到物体的顶部——就像你在平台游戏中所做的那样——你的游戏如何知道这个角色是站在一片草地上还是站在一个盒子顶上?您可以使用碰撞检测或点击检测来实现这一目的。

在下一个例子中,我们将创建一个名为objectCollisionExample.py的全新 Python 文件。我们将从我们的pygameAnimations.py程序中借用一些代码。我将从粘贴整个程序开始,而不是向您介绍代码的每一部分,然后逐步介绍我们对旧代码所做的新的添加和修改。

花点时间创建新文件,并将以下代码复制到其中。在我解释之前,请务必阅读评论,看看您是否能弄清楚该程序的目的以及它是如何工作的。像往常一样,确保正确缩进代码,否则会收到错误:

# import our modules
import pygame
from pygame.locals import *
import sys

# Initialize our pygame modules
pygame.init()

# Create tuples for our colors
colorWHITE = (255,255,255)
colorBLACK = (0,0,0)
colorRED = (255,0,0)

# Create our main game window - last time we named it screen
# Let's give it a different name this time
gameWindow = pygame.display.set_mode((800,600))

# Set the caption/title for our animation
pygame.display.set_caption('Colliding Objects')

gameQuit = False

# Create two variables that will store sprite rectangle objects
rect1 = pygame.sprite.Sprite()
rect1.rect = pygame.Rect(300,300,50,50)

rect2 = pygame.sprite.Sprite()
rect2.rect = pygame.Rect(100,100, 100,150)

# Game Loop
while not gameQuit:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameQuit = True
            pygame.quit()
            sys.exit()
        # If the player presses 'q', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                pygame.quit()
                sys.exit()
        # If the player presses 'ESC', it is considered a quit event
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
        # If arrow key left is pressed, move the object left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                rect1.rect.x = rect1.rect.x - 10
        # If arrow key right is pressed, move the object right
            if event.key == pygame.K_RIGHT:
                rect1.rect.x = rect1.rect.x +10
        # If arrow key up is pressed, move the object up
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                rect1.rect.y = rect1.rect.y -10
        # If arrow key down is pressed, move the object down
            if event.key == pygame.K_DOWN:
                rect1.rect.y = rect1.rect.y +10

        # Check for collision between our two rect objects
        # using collide_rect
        # If a collision is detected, we relocate rect1
        # by changing its y and x coordinates
        if pygame.sprite.collide_rect(rect1, rect2):
            rect1.rect.y = 400
            rect1.rect.x = 400

        # Check to see if we collide with the right screen end
        # If it does, we move rect1 back to X coordinate 740
        if rect1.rect.x > 750:
            rect1.rect.x = 740
            pygame.display.set_caption('Right Collision')
        if rect1.rect.x < 1:
            rect1.rect.x = 51
        # Check to see if we collide with the left screen end
            pygame.display.set_caption('Left Collision')
        # Check to see if we collide with the bottom of the screen
        if rect1.rect.y > 550:
            rect1.rect.y = 540
            pygame.display.set_caption('Bottom Collision')
        # Check to see if we collide with the top of the screen
        if rect1.rect.y < 1:
            rect1.rect.y = 50
            pygame.display.set_caption('Top Collision')

    # Fill the gameWindow with the color white
    gameWindow.fill(colorWHITE)

    # Blit our rectangle objects
    pygame.draw.rect(gameWindow, colorBLACK, rect1)
    pygame.draw.rect(gameWindow, colorRED, rect2)

    # Update our screen
    pygame.display.update()

这段代码在大多数方面都像前面的程序一样;我们创建一个矩形对象——这次插入到一个 sprite 中——我们将使用箭头键在窗口中移动它。如果矩形接触到窗口的任何边缘或边界,矩形将从“墙”反弹几个像素

除此之外,我们还创建了第二个矩形对象——rect2——它是静态的,不会在棋盘上移动。我们还设置了代码来检查rect1是否碰到 rect2 如果是这样,那么我们改变 rect1 的XY坐标的值——就好像它撞到了一堵墙。

这段代码与前面的点击检测示例的主要区别在于我们创建矩形对象的方式。这一次我们不是简单地使用.rect来块化我们的矩形,而是想要实际创建一个变量来保存我们的矩形对象。

此外,我们制作这些矩形精灵,这样我们就可以访问一些pygame.sprite.Sprite()自带的内置函数。有许多内置函数伴随着pygame.sprite模块,不幸的是我们在本书中没有足够的空间来涵盖它们。然而,我们将触及一个非常重要的问题,它的目的是帮助碰撞检测。

通过将矩形对象存储在变量中并使它们成为精灵,我们可以通过直接访问这些属性来改变它们的 XY 坐标。

比如在程序的代码中,你可能会看到类似于rect1.rect.x = 100的东西。这段代码基本上是说,您想要获取名为rect1的变量,访问存储在其中的rect对象,并将它的x值更改为100

我们代码的这一部分:

rect1 = pygame.sprite.Sprite()
rect1.rect = pygame.Rect(300,300,50,50)

rect2 = pygame.sprite.Sprite()
rect2.rect = pygame.Rect(100,100, 100,150)

用于创建我们的两个矩形对象—rect1rect2。请务必注意,当我们使用pygame.Rect时,与我们在rect1.rect中使用时相比,“R”是大写的。未能正确利用它将导致错误。

下一个变化是我们如何定义对象(尤其是 rect1)在窗口中移动的方式。

由于我们的rect对象现在是一个精灵,我们必须以不同的方式访问它的参数——比如它的 XY 坐标。现在,要让物体移动,我们用这个方法:

        # If arrow key left is pressed, move the object left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                rect1.rect.x = rect1.rect.x - 10

请注意如何不使用?move_ip 方法,我们现在只需将 rect1.rect.x 的值重新分配给一个新值,如下所示:

                rect1.rect.x = rect1.rect.x - 10

它表示获取rect1的当前X坐标值,并从中减去10

我们对四个方向箭头的每个按键事件都这样做,并根据用户移动矩形的方向来改变rect1.rect.xrect1.rect.y的值。

请记住,X值代表左右移动,而Y值代表上下移动。

下一步是使用碰撞检测来查看rect1是否曾经接触过rect2。这就是将矩形对象定义为精灵派上用场的地方。sprite 对象的内置函数之一是collide_rect,它有两个参数:您希望检测碰撞的两个对象的名称。

我们在一个if语句中使用这个,这样我们就可以检查对象是否曾经接触过彼此。如果他们这样做,我们改变 rect1 的XY坐标的值为400 x 400,传送它远离rect2物体。这一切都是通过这段简单的代码完成的:

        if pygame.sprite.collide_rect(rect1, rect2):
            rect1.rect.y = 400
            rect1.rect.x = 400

最后,我们对代码做的最后一个改变是我们处理游戏窗口边界冲突的方式。它与之前基本相同,除了,再次,不是改变move_xmove_y的值来改变坐标或我们的矩形,我们直接访问矩形的 XY 参数。

如果检测到墙壁碰撞,我们只需将矩形向后移动几个空格:

例如:

if rect1.rect.x > 750:
            rect1.rect.x = 740
            pygame.display.set_caption('Right Collision')

表示如果 rect1 的 X 坐标大于750,则将 rect1 移回 X 坐标740,然后将窗口标题改为“右碰撞”

继续测试该程序,通过尝试从顶部、底部、左侧和右侧将 rect1 对象移动到 rect2 对象,确保检查碰撞检测对两个对象的所有四个侧面都有效。

然后测试窗口边界的碰撞检测,确保再次检查顶部、底部、左侧和右侧边界。

如果代码不起作用,重读一遍并进行比较,确保它匹配。

和往常一样,要注意缩进。

在这一集里!

在过去的两章中,你完成了一些真正令人惊讶的事情,看起来你正在成为一个不可阻挡的英雄!虽然我们没有在最后两章中涵盖所有可能的游戏主题——这需要一整本书(如果不是更多的话)来完成——但我们确实触及了足够的信息,让你设计一个基本的视频游戏,更重要的是,开始做你自己的研究来创建你自己的复杂游戏。

你的作业?走出去,创造一个有趣的游戏,或者至少是一个游戏的框架。我期待着当你成为世界著名的游戏开发者时,在 Playstation 402 或任何系统上玩它!

十三、错误处理

我们正在迅速接近这本书的结尾,我们的时间一起冒险。很快,你将独自披上斗篷,在没有我的帮助下与邪恶的人战斗(当然,这只是你的想象!),而且全靠自己写代码。

治愈悲伤的音乐。

尽管现在,我们仍然是超级英雄组合!虽然我们已经学会了如何击败许多编程恶棍,克服许多不同的障碍,但有一个话题我们仍然需要讨论:如何克服我们自己的失败。

你说失败?什么样的英雄或程序员会失败?

可悲的是,我们都有。或者,从更好的角度来看:幸运的是,我们都有。

为什么幸运?因为失败是让我们变得更强大、提高技能和编程能力的最好方式之一。

想想这个:你知道为什么举重会练出肌肉吗?这是因为你撕裂的肌肉需要愈合。当你举重时,在某一点上你达到了一个你不能再举的点——也就是说,你失败了。这种失败正是健身者所期待的,因为他们知道只有当你的肌肉失败时,它们才能开始修复损伤并变得更加强壮。

你的编程技巧一模一样。在我看来,真正理解代码的唯一方法是把它搞砸,然后找出你做错了什么。任何人都会这门语言——然而,理解这门语言需要多年的失败。

注意,同样的逻辑不适用于你的代数考试…不要不及格!

到目前为止,当我们遇到问题时,我们只是阅读我们的。py 文件,一行一行,试图找出哪里出了问题。老实说,没有真正的失败——只要你完全按照我写的输入我的例子。

然而,很可能是你打错了一两个单词,导致你的程序失败。在那之后你所做的——如果你已经做到了这一步——就是搜索你的代码,寻找引起问题的罪魁祸首,拼写错误的单词或缩进,然后修复它。

如果发生了这种情况,那么恭喜你——你已经正式测试并调试了一个程序,即使只是在最基本的意义上。

调试对我们来说是一个新词。它意味着从我们的代码中识别和删除错误。

让我们再来看看这个定义:从我们的代码中识别并移除错误。

对我来说,调试过程中最重要的部分是找到错误。从那里,我们必须了解错误,只有这样,我们才能修复或消除导致错误的问题。

对于小程序,我们可以逐行查找问题。对于较大的程序,我们会希望使用一个叫做调试器的程序。

查找错误

Python 通常很擅长告诉我们我们把事情搞砸了。对于本节,让我们继续创建一个名为Oops.py的新文件。

这个文件将会充满错误,当你运行你的程序时,你会被 IDLE 吼到。当我们键入我们的代码时,代码中的错误对你来说可能很明显,也可能不明显;不管怎样,跟着做,如果你看到了错误,假装你没有看到;它将帮助您了解如何更好地修复程序。

Oops.py中输入以下代码:

print hello

对于精明的程序员来说,你可能已经看出问题了;如果是这样,恭喜你,但假装你没有。继续运行程序,看看会发生什么。完了?你收到错误信息了吗?你当然知道!它应该是这样的:

Missing parentheses in call to 'print'. Did you mean print(hello)?

这应该显示为弹出消息。如你所见,IDLE 非常聪明——它不仅发现了你的代码中存在的问题,还为你提供了如何修复它的建议。

这里需要注意一些事情。首先,虽然 IDLE 在这里确实提供了一个建议,但它实际上是不正确的。由于我们没有将想要打印的文本用引号括起来,IDLE 假设我们真的试图打印一个变量,并向我们展示了如何打印一个名为hello的变量。

在这种情况下,这不是我们的意图,但 Python 指出错误并提供可能的解决方案还是不错的。

我们真正想要做的是打印出单词“hello”,这当然就像键入 print(“Hello”)一样简单。然而,请记住,我们希望我们的程序失败。

那么第一个错误的教训是什么?有时 IDLE 会在弹出消息中给我们一个错误消息,并建议错误发生的位置和可能的解决方案——可能正确也可能不正确。

现在,让我们修改文件中的代码,使其与下面的代码匹配:

print("Hello)

同样,您可能已经发现了问题——我们忘记用第二个或结束引号来结束我们的print()函数——但是继续运行程序看看会发生什么。

这里,我们再次看到另一个弹出窗口。这一次,我们得到了一种不同类型的错误——生产线末端(EOL)错误。它应该说:

EOL while scanning string literal.

在这里,Python 基本上是在告诉我们,我们没有正确地关闭这条线,我们知道我们没有这样做。如果我们单击弹出窗口上的“OK”按钮,IDLE 应该会将我们带回到我们的文件,并以红色突出显示该行的其余部分——这表明它认为该区域有错误。

我们知道问题在于我们只是忘记了我们的第二个引号。我们将解决这个问题,但是这一次,让我们去掉第二个括号,看看会发生什么。编辑您的代码以匹配以下内容,然后再次运行:

print("Hello"

这一次,我们得到另一个错误弹出窗口。这是一个文件尾(EOF)错误,它说:

解析时出现意外的 EOF。

这一次,当我们单击“OK”时,Python 突出显示了代码下面的行。为什么会这样?

当我们运行我们的代码时,Python 在寻找我们代码行的结尾——它应该是一个右括号。相反,它没有发现关闭,所以它跳到下一行寻找更多的代码。当它也没有找到右括号时,它认为我们弄错了,并突出显示了这一行,告诉我们它在哪里遇到了错误。

这很重要,因为通常我们认为 Python 是在向我们展示错误在哪里;事实上,Python 向我们展示了它出错的地方(那是一个词吗?).把它想象成从跳水板的边缘跑下来;从跳板上下来的第一步就是你搞砸的地方,但是你可能直到在全班同学面前笨拙地俯卧并脱掉泳裤的那一刻才意识到这一点。

Python 也是如此。

下一个错误。

现在,让我们修改代码,使其与以下内容匹配:

prant("Hello")

保存文件并运行它。这次没有弹出窗口——我们一定做得很好!

不完全是。

这一次,当程序试图在 Python Shell 中运行时,我们会得到以下结果:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 1, in <module>
    prant("Hello")
NameError: name 'prant' is not defined

这种类型的错误称为命名错误。让我们仔细检查输出的每一部分。

第一行写着:

追溯(最近一次通话持续时间):

这是 Python 告诉你它正在追溯代码中的错误,最后一个调用出现在最前面。这一轮我们只有一个错误,但是不要担心,我们马上会有多个错误。

接下来,Python 告诉我们一些重要的信息。它告诉我们文件的位置(你的和我的不同)以及它认为错误在哪一行。在这种情况下,它表示第 1 行,即代码的第一行。

接下来,它向我们展示了发生特定错误的代码:prant("Hello").

最后,它告诉我们错误的类型,并提供了更多的细节:名称“prant”没有定义。

当我们看到这样的消息时,意味着 Python 看到了:

prant()

并且在其内置函数列表中找不到它。原因?因为它不存在——我们拼错了print(),虽然我们知道这一点,但 Python 无从得知。

由于 Python 没有找到名为prant()的内置函数,它假设我们正在尝试调用我们创建的名为prant()的函数。因为我们没有使用那个名称创建函数,所以 Python 认为我们输入了错误的名称或者没有定义那个名称的函数。

这是一个非常基本的错误,对于我们来说,跟踪和修复它非常简单。我们要做的就是看第 1 行,找到乱七八糟的代码,把prant("Hello")改成print("Hello")。然后,如果我们保存了它,我们可以运行它,一切都会好的。

当然,我们现在还不需要这么做,因为我们仍然在代码中故意犯错。

在我们继续之前,让我们看看我们是否能犯更多类型的错误。再次修改您的代码,使其符合以下内容:

a = 1

whilst a < 4:
    print(a)
    a = a + 1

这段代码应该做的是将值 1 赋给变量“a”。然后,我们创建了一个while循环,只要'a'的值小于4,它就会进行迭代或重复。

对于这个循环的每一次迭代,'a'的值被打印出来,我们还将+1加到'a'的值上。理论上,这段代码的输出应该是:

1
2
3

然而,我们在代码中犯了另一个错误——这次你能发现它吗?

如果您运行该代码,您将得到一个弹出框形式的提示,内容如下:

invalid syntax.

那到底是什么意思?这意味着我们在代码中拼错了。同样,我们用红色高亮显示我们的区域在哪里。

问题?我们把while拼成了,而不是

让我们修正的拼写,但是在它的位置上犯另一个错误。编辑代码,使其与以下内容匹配:

a = 1
while a < 4
    print(a)
    a = a + 1

这次你能发现错误吗?保存文件并运行代码。再次,我们得到一个语法错误,即使我们修正了while的拼写。其他每个单词的拼写都是正确的,这是怎么回事呢?

语法错误包括一般的拼写错误,而不仅仅是拼写错误。在这种情况下,我们忘记在 while 语句的末尾添加一个冒号:。这一行应该是:

while a < 4:

如果您在末尾添加冒号并保存文件,它应该可以正常运行。

错误类型

实际上,Python 中只有三种主要的错误类型:语法错误、逻辑错误和异常。我们将在本节中介绍每种错误类型以及如何处理它们。所以,带上你的超级英雄护目镜,让我们准备好解决这个世界的问题吧!

好吧,好吧——也许只是我们代码中的问题。

句法误差

我们已经在前面的错误概述中讨论了一点语法错误。提醒您一下,当 Python 无法理解或读取一行代码时,会出现语法错误。

语法错误通常是由简单的打字错误引起的;也许您拼错了一个函数,或者忘记在语句末尾添加一个冒号。把它们当成语法或拼写错误。

在您收到的所有错误中,语法错误可能是最常见的。这有好有坏;这很好,因为这意味着,大多数情况下,你的错误只是拼写或标点符号的问题,而不是编程逻辑的问题。这很糟糕,因为,嗯,追踪它们可能会很烦人,尤其是在你整天夜以继日地输入代码后,你的眼睛会变得模糊。

绝大多数语法错误都是致命的,会导致代码无法执行,这也是塞翁失马焉知非福。虽然你的代码根本不工作可能很烦人,但这也确保了你不会发布一个有隐藏问题的软件。

如果遇到语法错误,请注意 IDLE 中突出显示红线的位置,或者注意出现错误的行号,并查找拼写、缩进、冒号、引号和括号使用方面的任何问题,或者无效参数。

逻辑错误

所有错误中最成问题的是可怕的逻辑错误。顾名思义,当您的编程逻辑中存在缺陷时,就会出现这种情况。这些类型的错误会导致你的程序行为古怪或者彻底崩溃。

逻辑错误如此令人沮丧的部分原因是,它们并不总是导致明显的错误。有时 Python 甚至没有捕捉到错误,而您自己可能会错过它。这就是为什么频繁测试代码并尽可能提供文档是如此重要。

有几种方法可以发现这些类型的错误,包括使用一个调试程序,我们将在本章的后面介绍。处理逻辑错误的最好方法是首先防止它们。我们通过提前规划程序和频繁测试来做到这一点。使用流程图可以帮助您确定代码的每个部分应该如何流动,并且是避免逻辑错误的有用工具。

当然,逻辑错误还是会发生;这只是作为程序员的一部分。

这是一个逻辑程序的例子——看看你是否能找出为什么这个程序会返回一个不是预期的结果。这里有一个提示:这个程序的目的是找到两个数字的平均值:

a = 10
b = 5

average = a + b / 2

print(average)

如果你不擅长数学,不要担心;当我们写这个程序时,我们期望 10 和 5 的平均值是 7.5;然而,当我们运行这个程序时,我们得到的结果是:

12.5

这当然是不对的。为什么会这样?让我们检查一下我们的数学,看看我们的计算是否正确。

如果我们在一张纸上写下这个等式,我们会写出 a+b/2——就像我们看到的那样。a + b 等于 15,除以 2 等于 7.5 对吗?

如果您还记得我们关于数学运算符和数字的讨论,那么在 Python 中,数学并不总是与使用笔和纸时一样。在 Python 中,有一个优先顺序,这意味着 Python 查看一个等式,并确定在继续下一部分之前先解决哪个部分。

如果这一部分不清楚,我鼓励你回到处理操作符和数字的那一章,再复习一遍。有意义的时候再回来。

为了让 Python 按照我们想要的顺序执行等式,我们需要使用括号()强制优先级顺序。在不出现逻辑错误的情况下,编写这段代码的真正方法应该是:

a = 10
b = 5

average = (a + b) / 2

print(average)

这一次,如果您运行代码,您将得到:

7.5

对于那些对数学不感兴趣的人,或者那些睡眠不足的人,你可能完全忽略了这个事实:这段代码根本没有正常运行。Python 根本没有发送警告或错误消息,所以如果我们不测试结果并仔细检查以确保它们是正确的,我们就没有真正的方法知道有问题。

现在想象一下,如果这是一个银行应用的一部分,您会看到一个简单的逻辑错误会如何毁掉整个系统,并让许多人非常难过!

例外

异常是一种特殊的错误。有几种类型的内置异常,但它们太多了,本章无法一一介绍。相反,您可以访问 Python。org 关于内置异常的文档页面位于 https://docs.python.org/3/library/exceptions.html#bltin-exceptions 查看不同的类型。一会儿我会解释为什么这可能比你想象的更有用。

现在,要知道当 Python 理解你的代码,但是不能执行基于它的动作时,异常就会发生。例如,也许你正试图连接到互联网,从网站上删除或复制一些数据,但你无法连接。或者你有一个脚本试图使用一个在你给它的地址上已经不存在的 API。

异常在许多方面不同于语法错误。其中之一是它们并不总是导致错误。这有好有坏;这很好,因为您的问题有时仍然可以异常运行;这是不好的,因为,嗯,你的程序有时仍然可以运行异常!

我们不希望我们的代码运行时出错!

关于异常的伟大之处——如果你想看到光明的一面——是我们可以做一些叫做异常处理的事情。处理一个异常基本上意味着我们预期错误可能发生,然后编写一个处理它们的方法。

假设我们有一个程序要求用户输入四位数的 pin 码。我们希望确保该值本质上是数字。我们已经将变量设置为专门保存一个整数值。让我们从基本代码开始:

pin = int(input("Enter your pin number: "))

print("You entered pin: ", pin)

如果你把代码放在一个文件中并运行它,它会要求你输入密码。继续尝试吧——如果你愿意,你可以把它添加到你的Oops.py文件中。首先,输入一个四位数,然后按下Enter。该程序将给出类似于以下内容的响应:

You entered pin: 1234

其中1234是您输入的任何数字。

现在,再次运行该程序,只是这一次,在提示时输入类似于“abcd”的内容,然后按下Enter

这样,您将获得以下输出:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 17, in <module>
    pin = int(input("Enter your pin number: "))
ValueError: invalid literal for int() with base 10: 'abcd'

这里,我们看到了一个类型为 ValueError 的异常错误。发生这种情况是因为 Python 期望在变量pin中找到的值的类型是整数;相反,你输入了一个字符串。

我们可以确保 Python 不会抛出这样的错误并迫使我们的程序不能正常运行的方法之一是提前处理错误。因为我们知道有人可能在我们的变量中输入了错误的数据类型,所以我们可以创建代码在错误发生时捕捉并处理它。

尝试键入以下代码,替换其他版本的代码,然后保存文件并运行它:

# Example of exception handling a ValueError

try:
    pin = int(input("Enter your pin number: "))
    print("You entered: ", pin)
except ValueError:
        print("You must only enter a numeric value.")

这在 Python 中被称为tryexcept块。它的具体目的是捕捉并处理异常。在某种意义上,块中包含的代码被小心处理;Python 意识到你打算在错误发生时处理它,如果存在一个错误(你指定的类型),它就触发你的except语句。

继续运行这个程序,当再次提示时输入'abcd',看看代码现在是如何运行的。您应该会得到这样的回应:

Enter your pin number: abcd
You must only enter a numeric value.

一旦 Python 点击了 except 语句,它就会遵循您的指令,然后退出程序。在现实生活中,我们希望将这段代码放在一个循环中,这样如果出现异常,它就会重新开始。例如,您可以使用一个简单的 while 循环,如下所示:

# Example of exception handling a ValueError
repeat = 1

while repeat > 0:

    try:
        pin = int(input("Enter your pin number: "))
        print("You entered: ", pin)
        repeat = 0
    except ValueError:
        print("You must only enter a numeric value.")
        repeat = 1

Try Except Else 块

你可以做的另一件事是创建一个Try Except Else块。这背后的想法是,如果没有异常,代码将执行一组不同的指令。例如:

# Example of exception handling a ValueError
# Using a Try Except Else block
# Enclosed in a while loop

repeat = 1

while repeat > 0:

    try:
        pin = int(input("Enter your pin number: "))
    except ValueError:
        print("You must only enter a numeric value.")
        repeat = 1
    else:
        print("You entered: ", pin)
        repeat = 0

这与之前版本的程序有着相同的结果和相似的工作方式。区别?它更简洁,可读性更强。它基本上读作:

Try this code. If it doesn't work:
Execute some code if an exception occurs.
Else if there are no exceptions, run this code.

最终使用

我们还可以添加一个东西到我们的块中——finally子句。当我们希望一些代码无论如何都要运行时——即使有错误——?? 是有用的。

# Example of exception handling a ValueError
# Using a Try Except Else Finally block

try:
    pin = int(input("Enter your pin number: "))
except ValueError:
    print("You must only enter a numeric value.")
else:
    print("You entered: ", pin)
finally:
    print("Are we done yet?")

为了更好地研究这段代码,我们移除了与repeat相关的while循环和repeat变量/代码。基本上这段代码是这样说的:

Ask for a pin number that is an integer value.
If the pin number is not an integer,
Trigger the except statement.
Else print the value of the pin number.
Additionally, no matter what,
Trigger the finally clause.

如果输入'abcd'并触发异常,这段代码的结果将是:

Enter your pin number: abcd
You must only enter a numeric value.
Are we done yet?

如果您再次运行它并输入'1234'作为您的 pin,它将导致:

Enter your pin number: 1234
You entered:  1234
Are we done yet?

无论哪种方式,你都会注意到,我们的finally子句被触发——正如预期的那样。如果您预料到了异常错误,这是让您的程序继续运行的好方法。

创建自定义例外

除了从定义的内置异常列表中设置处理异常,我们还可以创建一个自定义异常。为此,我们使用raise。这里有一个简单的例子:

super_name = "Afraid-of-Spiders-Man"
villain = "spiders"

if villain == "spiders":
    raise Exception("Yeah, no thanks...my name says it all...villain should NOT equal spiders!")

这里我们开始创建两个变量。一个保存着我们的超级英雄的名字—super_name,而另一个保存着我们的英雄将会遇到的反派类型—villain

接下来,我们执行一个 if 检查,看看villain的值是否等于'spiders'(毕竟,我们的英雄叫害怕蜘蛛的人!).因为villain确实匹配'spiders',所以我们使用raise来创建一个例外:

当我运行代码时,我得到以下错误:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 33, in <module>
    raise Exception("Yeah, no thanks...my name says it all...villain should NOT equal spiders!")
Exception: Yeah, no thanks...my name says it all...villain should NOT equal spiders!

注意

您可以忽略本例中的行号——我的文件中有其他代码,使错误出现的行号与您的不同。

这里我们看到异常错误被引发,打印出一些文本,内容如下:

Exception: Yeah, no thanks...my name says it all...villain should NOT equal spiders!

在这个例子中,我试图变得有趣,所以我破例说了一个笑话。实际上,当您创建自己的例外时,您会让他们说一些类似以下的话:

Exception: the villain variable contains a value that is not allowedspiders

这样,如果有人输入了错误的值,我们可以在查看异常时立即知道问题是什么,而不必追踪问题。

我们可以创建的另一种自定义异常是AssertionError异常。这种类型的异常通过断言给定条件为True或满足来启动程序。如果是,那么程序可以继续运行。否则,将引发 AssertionError 异常。

请考虑下面这段简短的代码:

assert 1 + 1 == 2, "One plus One does equal 2!"
assert 2 + 2 == 5, "2 + 2 does not equal five! Error in line 2!!"

这里我们有两个assert语句。如果我们运行这个程序,程序的第 1 行什么也没有发生——这是因为等式 1 + 1 实际上等于 2,所以断言条件测试等于True

当试图执行第二行代码时,assert测试条件证明了False (2 + 2 不等于 5),因此触发 AssertionError,产生以下输出:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 2, in <module>
    assert 2 + 2 == 5, "2 + 2 does not equal five! Error in line 2!!"
AssertionError: 2 + 2 does not equal five! Error in line 2!!

为了方便起见,我继续添加了代码中的错误写在了assert的输出中,以及引发 AssertionError 的原因。

记录

我们可以使用的另一个工具是使用logging来查找代码中的错误——特别是对于较长的程序。有几种方法可以做到这一点,但是最简单的方法可能是导入logging模块。

程序员用来减少代码中错误的一种方法是使用print()来验证一切都正常工作。例如,假设我有一组随机生成的统计数据——正如我们在超级英雄生成器 3000 应用中所做的那样。

我可以相信我的代码工作正常,并假设统计数据是随机生成的,但这可能不是最明智的做法。为了确保我正确地编写了所有代码,我可能希望随机生成姓名,然后临时插入一些代码来打印这些统计数据的结果。一旦我对随机数生成工作正常感到满意,我就可以删除所有的print()并继续我的代码。

例如,我可能会先编写以下代码:

import random

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

brains = random.randint(1,20)
braun = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

然后,意识到我需要检查所有的值是否正确随机化,我可能会返回并编辑我的代码来添加这些print()函数:

import random

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

brains = random.randint(1,20)
print("Brains: ", brains)
braun = random.randint(1,20)
print("Braun: ", braun)
stamina = random.randint(1,20)
print("Stamina: ", stamina)
wisdom = random.randint(1,20)
print("Wisdom: ", wisdom)
constitution = random.randint(1,20)
print("Constitution: ", constitution)
dexterity = random.randint(1,20)
print("Dexterity: ", dexterity)
speed = random.randint(1,20)
print("Speed: ", speed)

然后我可以做的是运行程序一次,看看变量中是否存储了值,给我结果:

Brains:  19
Braun:  19
Stamina:  2
Wisdom:  11
Constitution:  14
Dexterity:  12
Speed:  6

然后,对值被添加感到满意,我将再运行一次测试,以确保每次程序运行时值都被随机化。测试很简单:如果第二次的值不同,就可以了。结果呢?

Brains:  20
Braun:  2
Stamina:  14
Wisdom:  18
Constitution:  6
Dexterity:  19
Speed:  3

因为在我的两次测试中,每个 stat 的值都不同,所以我可以假设我对random的使用是正确的。我不再需要我的print()函数。我可以将它们注释掉,或者完全删除它们。

由于这是一段简单的代码,我将继续删除print()函数,这样我的代码可读性更好。

与其用一堆 print()函数把我的文件弄得乱七八糟,我可以使用日志来监视文件,并将结果写入一个单独的文本文件。

日志记录的另一个好处是我们可以记录代码中发生的事件和错误,以备将来出现新的 bug 或者我们需要查看日志。

值得注意的是,日志记录不仅仅是监视警告和错误;它对于监控触发事件也很有用。

事实上,logging模块有自己的一套“重要程度”等级,您可以在记录时使用。它们是:

Critical:用于可导致程序出现严重问题或根本无法运行的严重错误。

错误:对于严重的非关键问题

警告:用于意想不到的事情已经或可能发生的时候

Info:用于确认您的代码正在按预期运行——类似于我们对print()语句的使用

调试:有助于诊断任何问题,并提供可能有助于调试过程的信息

事实上,日志尤其是日志模块的使用超出了本书的范围。要用整整一章的时间来解释它的用法,虽然我鼓励初学者学习日志,但它根本不适合我们的课程。

也就是说,留出一些时间来阅读关于日志和logging模块的官方 Python 文档。此外,在创建更复杂的程序时,可以看看互联网上的一些教程和其他更高级的书籍,并开始涉猎日志记录。

把你的脚趾伸进去,当你感到舒服的时候,就开始潜水吧!

Python 调试工具

我们讨论了很多关于修复代码中的错误、测试代码以及如何执行异常处理的内容。我们还讨论了日志记录和使用logging模块跟踪日志文件中的错误和事件的基本概念。

我们可以用来解决编码问题的另一个超级英雄锦囊妙计是一个叫做调试器的工具。有许多 Python 调试器可供选择,每一个都有自己的优点和缺点。有些涵盖 Python 的特定领域,选择专门化,而有些是通用调试工具,具有与其他调试程序类似的功能。

Python 其实有自己的调试工具,叫做pdb

从技术上来说,pdb是一个可以导入使用的模块。这个模块让你进入你的程序,一行一行地检查它们,看看它们是否正常工作。

还记得我们前面的例子吗,使用 print()语句来检查我们的 stats 随机值是否被正确分配?使用 pdb 调试器模块,您可以获得相同的结果,而不必编写所有这些print()语句。

您可以在 Python 的文档网站上了解有关 Python 调试器 pdb 模块的更多信息,只需确保您正在查看的文档版本与您计算机上安装的 Python 版本相匹配即可。以下是 Python 3.6 的链接,例如:

https://docs.python.org/3.6/library/pdb.html

Python 3.7 以断点()命令的形式对 pdb 模块进行了一点升级:

https://docs.python.org/3.7/library/pdb.html

与日志记录一样,您应该学习调试,并从现在开始学习基础知识,然后,当您创建更复杂的程序时,就可以更轻松地使用您最终选择的程序。现在,我会坚持使用pdb

处理错误的最后一个技巧

如果我以前没有说过,我想留给你最后一个发现和处理代码中错误的技巧:使用注释。

那到底是什么意思?

这个概念很简单:如果您怀疑某段代码给您带来了问题,使用注释(#)使代码行对 Python 不可见,然后运行您的代码,看看问题是否仍然存在。如果没有,你已经发现了你的问题;如果问题仍然存在,继续下一段代码。

对于更复杂的结构,如 if 块,使用多行注释(“' '”)来注释掉整个部分。例如:

"""
IF
code
code
code
"""

会注释掉三引号(“”)之间的代码。

这是所有级别的编码人员都使用的一种常见做法。只是不要忘记在检查和/或修复代码后取消注释!

在这一集里!

你能相信我们已经走了这么远吗?离我们结束超级英雄的冒险只剩一章了!

超级!太棒了!惊人的!太神奇了!壮观!

轰!砰!嘭!索克-欧!

这一章是关于错误的:发现错误、修复错误、记录错误和调试错误。以下是这些主题的一些亮点,您可以在闲暇时回顾一下。

然后,就到了最后一章!

  • Python 中的三种错误类型是:语法错误、逻辑错误和异常。

  • 语法错误类似于拼写错误或语法错误;它们通常是致命的,会导致您的代码无法执行。

  • 当您的编程逻辑中存在缺陷时,就会出现逻辑错误。它们并不总是导致明显的错误,而是经常导致程序行为异常而不是崩溃。

  • 异常并不总是导致错误,尽管抛出了异常,程序仍然可以运行。

  • 有许多类型的内置异常,包括 ValueError 和 NameError。

  • 除了内置异常,我们还可以使用 raise 和 assert 创建自己的异常。

  • Try-except-else-finally 块允许您指定在遇到某些标准(或错误类型)时会发生什么,从而使您能够更好地控制错误的处理。

  • 异常处理是处理异常错误的过程。

  • 日志记录允许您跟踪代码中的错误、警告、调试信息和事件。您可以将这些日志文件保存到一个单独的文件中供以后使用。

  • 您可以使用日志模块来帮助记录。

  • Python 中有许多工具可以帮助您调试——或者找到错误并修复它们。

  • Python 的内置调试器是模块 pdb。

  • 您可以使用单行注释和多行注释来注释掉可能会(也可能不会)导致程序错误的代码块。然后您可以测试您的代码,看看这些注释掉的部分是否是罪魁祸首。

十四、Python 职业生涯

年轻的英雄,这是一个漫长的旅程。我们战胜了许多敌人——像杰克·汉默和邪恶的阿尔杰布罗这样邪恶的恶棍。我们通读了这本神秘的大部头,获得了洞察力和智慧,这使我们能够将我们的力量提升到前所未有的高度。我们在谈论珠穆朗玛峰类型的高度。

或者,至少,操场上那个很高的滑梯的顶部。

不管怎样,当我们第一次一起开始这次冒险的时候——这确实是一次冒险——你只是一个跟班,你的超级紧身衣上有芥末污渍,穿着皱巴巴的斗篷。你的面具,虽然色彩鲜艳,却勉强遮住了你的脸。

但是看看你现在!一个全面发展的英雄,充满了惊人的力量。你可以创建自己的程序,编写视频游戏,入侵(合乎道德的)计算机,完成伟大的数学壮举,随机生成统计数据,等等。

你已经从初出茅庐的英雄变成了超级英雄;从学生到…嗯,更好的学生。

但最重要的是,你已经从读者变成了程序员。我的朋友,这就是这本书的目的。

然而,即使你站在这个伟大的悬崖上,舒适地呆在你精心布置的超级英雄巢穴里,练习你新发现的力量和知识,你也绝不能休息。世界是一个不断变化的景观,技术也是如此。Python 也是一只不断进化的野兽,看不到尽头。

正因为如此,你必须继续练习你已经掌握的知识,直到它变得像第二语言一样。你需要用代码做梦!然后,走出去,学习更多的语言,做更多的梦!

Python 还有很多东西等待你去发现和成长。这本书只是冰山一角。你在书本上学不到的实际的、真实世界的经验正等着你。Python 的更新版本在等着你。

或许还有其他语言。

我鼓励你拓展业务,永远不要满足于自己的知识。看看其他语言。考虑学习一些 Perl,它非常类似于 Python,应该很容易上手。Ruby on Rails 和 PHP 也是很好的下一代语言,尤其是如果您希望扩展到 web 应用编程的话。

C 和 C++ 稍微难一点,但是非常值得努力学习,即使你只是学习基础。当你在做的时候,HTML、JavaScript 和 JSON 都是你应该添加到你的简历和技能集中的便利工具。

说到简历,这最后一章有一个真正的目的:让你为真实的编程世界做好准备。无论你是 13 岁还是 14 岁,迟早你都需要决定你希望在职业道路上朝着什么方向前进;知道你现在有哪些选择可以帮助指导你未来的学习道路。

例如,如果你决定从事游戏编程,继续学习 Pygame 和玩 Scratch 肯定会有帮助。添加像 C、JAVA 和 C++ 这样的语言是一个明确的要求——尤其是 C++。

在这一章中,我们将看看所有当前和未来的职业选择,以帮助你开始思考你成年后想做什么。我们还会看看常见的面试问题,针对那些已经成年并需要开始支付这些账单的人!

毕竟,你不能指望靠一份超级英雄的薪水就能成功…

我们还将更新我们对最佳编程实践的记忆,以便我们继续编写好的代码,并在获得它们后保住我们的工作。我再怎么强调好的编码原则的重要性也不为过。世界的未来取决于此!

说到未来(没错,我就是塞格王!),我们将看看 Python 作为一种语言的未来。我们将讨论它在虚拟现实(VR)、增强现实(AR)、人工智能(AI)以及一系列其他缩写中的作用,这些缩写让我们在说它们时听起来既时髦又酷。

最后,我们将用 Python 术语备忘单来结束这一章,并回答一些关于 Python 和编程的常见问题。

这是一条漫长的路,没有理由再走下去了。穿上你的超级英雄靴子,系好鞋带!是时候结束这段旅程了。

超级英雄风格!

使用 Python

当你拿起这本书的时候,你的脑海中可能有也可能没有职业道路,这没关系;许多人不知道他们长大后想做什么,直到他们过了成年的年龄!

无论你是否知道自己想成为什么,或者想从事什么职业,有一件事是肯定的:你关心那是什么。你投资了这本书,更重要的是,投资了你自己,这就是证据。你花时间阅读这些页面并尝试代码,这比你这个年龄的许多人迄今所做的都要多。对你有好处!

下一步是弄清楚你想用你获得的知识做什么。最有可能的是,你会想继续做一名 Python 开发人员,而不考虑你可能学习的领域或其他语言和技能。

你在职业生涯中所做的一些事情将取决于你选择之外的因素。你遇到的人,你生活的地方,和可获得的工作将会一直影响你的道路走向。你可能开始认为你会成为一名视频游戏程序员,在一家视频游戏开发公司实习,担任游戏测试员,以获得一些经验,并转向这条道路。谁知道呢——这是生活冒险的一部分!

这并不意味着你不能瞄准某个目标,甚至坚持下去。要知道,无论你的计划多么用心良苦,有时你可能会发现自己身处出乎意料的地方,这没关系。

除此之外,知道自己想去哪里是件好事。因此,记住这一点,让我们看看当你发展成为兼职超级英雄、全职程序员时,一些可能的职业选择。

Python 的职业道路

本节列出的职业道路没有任何特定的顺序;没有一个比其他的更好,尽管你可能会发现一些地区的工资比其他地区高。我们不会专注于此。我坚信做自己喜欢的事。如果你那样做了,成功就会随之而来。

这份清单绝不是决定性的;有相当多的职业可以选择,但这些是目前最常见的。

β系数测定器

测试人员是软件开发者世界的无名英雄。他们测试程序和软件,并从技术角度和用户体验角度找出哪些可行,哪些不可行。在某些情况下,你可能会被要求专门测试某个程序的某个特性或方面;在其他情况下,您可能需要检查一切。

编程知识对这个角色很重要,但不是最重要的。从编程语言的角度来看,我已经测试了许多我没有实际经验的程序;我理解这些概念和事情是如何运作的,这很好地服务于它的目的。

当然,如果你懂这门语言,并能准确指出代码中的问题,那就更好了,你可能会更容易找到工作。

很可能,你已经测试过软件,但可能还没有完全意识到。如果你是一个狂热的视频游戏玩家或手机游戏爱好者,你经常会在测试版向大众发布之前尝试它。虽然这与付费演出不太一样,但也有好处,比如免费的软件和/或硬件。

代码调试器/错误定位器

这听起来可能类似于 beta 测试人员,但在大多数情况下,它实际上更复杂一些。你的任务是:找出不可靠的、糟糕的代码,并报告如何修复它——或者自己修复,这取决于工作。

如果你是那种喜欢花几个小时试图解决程序有什么问题的人,或者喜欢把东西拆开的人,这可能是你一个很好的职业选择;至少,这是一项很好的技能,不管你的职业道路会把你带到哪里。

请记住,你将会浏览其他人的代码,有时还会浏览多个人的代码。希望这些人能够很好地记录文档并遵循标准的指导方针,但是你永远不知道你会遇到什么。

尽管如此,这仍然是一种保持领先的好方法,如果你成为一名软件开发人员或创建自己的应用,善于发现程序中的错误将会派上用场。

数据科学家

如果你擅长统计、数字和研究,你可能会考虑进入数据科学领域。Python 在数据科学的世界里是巨大的,这是统计学和机器学习技术的混合物。

得益于其庞大的数学和数据可视化工具库(如 matplotlib 和 NumPy),Python 程序员在数据科学职业方面处于领先地位。在这一行中,您将使用图表和其他工具来帮助组织、解释和显示各种行业和应用的数据集。

您开发的算法和您对数据的解释有助于组织或企业做出关键决策。在这条职业道路上,你需要一个善于分析的大脑,良好的数学技能,当然,还需要一点编程知识,但对于那些喜欢弄清楚信息真正含义的人来说,这肯定是一个有回报的领域!

软件开发人员/软件工程师

当成为一名软件开发人员时,有很多选择。这可能是你在考虑自己在大计划中的位置时首先想到的角色。

软件开发人员创造了大量的软件,包括生产力应用(如微软 Office)到音乐创作程序以及你能想到的几乎任何东西。只要看一眼你电脑上的应用,你就会对这个范围有多广有所了解。

如果你决定成为一名软件开发人员或软件工程师,请记住,你会想尽可能多地学习 Python 和其他语言;了解其他语言和框架不会有什么坏处,另外,一旦你了解 Python,学习第二种或第三种编码语言会变得容易得多,因为许多逻辑和结构在不同语言之间是相同的;这主要是学习新的语法和编程风格的问题(例如,不是每种语言都使用缩进)。

视频游戏程序员

虽然这个职业在技术上与软件开发人员属于同一条道路,但我想我应该特别提到它。作为一个电子游戏的狂热爱好者——毕竟,这是我最初进入编程的原因——如果我不把它作为一个独立的职业选择,那我就失职了。

在过去的十年里,视频游戏的发展真的很繁荣。事实上,当我在大学的时候,只有少数几个学院——大部分是专业——提供游戏开发的课程,更不用说学位了。事实上,我的大学只开设了一门这样的课程——而且一年只有一次!

当然,我们过去都是在巨石上凿我们的代码,那时我们鼻子里戴着骨头,但是仍然…

如果你想为主流主机开发,你需要知道的不仅仅是 Python 和 Pygame。事实上,虽然 Python 肯定会帮助您理解所需的一些逻辑,但您确实需要扩展到 C++ 并涉足一些 C 和 JAVA。

如果你选择走非主机游戏或 PC 游戏的路线,你可能会有更多的选择,但实际上,在撰写本文时,C++ 才是正确的选择。

移动开发

虽然 Python 不是您可能想到的第一种移动开发语言,但是您确实可以使用该语言来创建应用和/或与其他更擅长移动应用开发的语言结合使用。

移动应用包括您在手机或平板电脑上使用的任何应用。这可能是游戏、messenger 应用、新闻阅读器应用、银行软件,甚至是网站的移动版本——清单还在继续。

如果你选择了这个重要而巨大的市场,你将会很好地学习真正的移动开发语言:C#或 Objective-C、C++、JAVA、Swift,甚至 HTML5。为了简单起见,您可能希望从 HTML5 开始,因为它可能比列表中的其他语言更容易学习。你也可以使用 HTML5 进行 web 开发,所以如果你发现移动应用开发不适合你,这是一个非常方便的工具。

当然,C++、C 和 JAVA 也会为你打开其他的大门,但是它们学习起来稍微复杂一些,所以这完全取决于你的时间框架和需求。

无论哪种方式,只要知道您可以使用 Python 进行移动开发,即使它的这种用途并不广为人知。

网络开发和网络应用

如果您想创建基于 web 的应用,Python 当然可以在这方面提供帮助。事实上,Python 真正的优势之一是它的一系列强大的 web 框架,比如 Django 和 Flask。这些框架充当某种蓝图或框架,让您快速部署应用的“骨骼”,节省您大量的设置和编码时间。基本上,它们为您创建了 web 应用中的基础,因此您不必重新发明轮子。

将 Python 和 web 框架与 HTML5 以及一点 JavaScript 结合起来,你将成为互联网世界中不可忽视的力量。例如,Google、YouTube 和 Yahoo 的平台都依赖于 Python。如果这还不能告诉你 Python 有多好,我不知道还有什么能告诉你!

系统管理员

而系统管理员(或者系统管理员,如果你敢!)是一群有趣的人,他们也是任何组织中非常必要的一部分。您可能已经猜到了,Python 非常擅长帮助系统管理员完成工作。

系统管理员使用 Python 来创建工具和工具,帮助他们管理计算机系统、控制操作系统和处理网络任务。

它还允许您创建自己的服务器和客户端、消息传递系统等等。Python 是迄今为止系统管理员最好的朋友。

那个,还有猫,出于某种原因…

研究、教学等等

Python 也是一个很好的研究工具,正如数据科学家一节所提到的。它有如此多的库和工具来处理复杂的方程和数据集,难怪 NASA 如此依赖这种语言。

更重要的是,在学校或大学环境中教授 Python 始终是一种谋生的好方法,同时也是向后代传授知识的好方法。它很容易学习,而且作为副产品,也很容易教,这是计算机科学课程要求中非常常见的第一步。

谁知道呢…如果你教得足够多,也许有一天你可以写一本关于它的书。

你知道吗…算了吧。把这本书留给我写;我有狗要喂!

常见的 Python 面试问题

对于一些正在阅读这本书的人来说,你不必担心在面试中会被问到什么样的问题;对于其他人来说,这将是一个非常现实的问题,宜早不宜迟。无论哪种方式,无论你是准备进入职场,还是还太年轻而不能考虑这样的事情,我们建议你花时间学习和思考本节中常见的 Python 面试问题列表。

虽然这本书涵盖了很多这样的主题,但还有很多没有;记住,这是一本初学者的书,旨在教你开始用 Python 编程所需要的东西。这并不意味着让你全副武装地去工作。

如果有任何术语或想法没有意义,我们建议您使用谷歌搜索,在其他书籍中查找,并尽可能多地学习。这些问题和答案不仅仅是为了帮助你通过作弊找到工作,因为你擅长记忆;事实上,这些问题是常见的面试问题,因为它们回避的概念是重要的编程原则。

因此,知道这些问题的答案——进一步,通过学习和实践真正理解它们——不仅会帮助你在准备好的时候找到工作,还会帮助你在那份工作上保持甚至茁壮成长!

你能告诉我 Python 的一些关键特性吗?

这是一个看似简单的问题。面试官想看看你对 Python 的了解程度,你对这门语言有多感兴趣,以及你对它的通用特性了解多少。虽然您可以指出很多,但最常见的是:

  • Python 是一种解释型语言,这意味着它不需要像某些其他语言一样在运行之前进行编译。

  • Python 是一种多用途语言,能够用于广泛的领域,包括数据科学、道德黑客、系统管理、web 开发、移动应用开发、视频游戏编程、科学建模等等。

  • Python 可读性强,简单易学,但功能强大。它是一种面向对象的语言,是动态类型的(这意味着不需要定义你声明的变量的数据类型;Python 在很大程度上可以检测出您想要的数据类型)。

元组和列表的区别是什么

我们在前面的章节中讨论过这个问题,答案非常简单:元组是不可变的,这意味着它们的值不能改变。同时,列表是可变的,这意味着你可以改变它们的值。另一个区别是元组需要圆括号(),而列表使用方括号[]。最后,虽然人们可能不会注意到,但从技术上讲,列表比元组慢。

什么是继承?

我们在处理对象和类的章节中讨论了继承的概念。您可能还记得,类遵循层次结构,类似于父子关系。当我们有一个父类或者超类时,这个父类的子类继承了父类的属性和方法。

记住:类和对象——面向对象编程(OOP)的一个关键特性——都是关于代码可重用性的。一个子类可以从一个父类或多个父类继承,从而具有很大的灵活性和很高的编码效率。

在 Python 中如何生成随机值?

我们在本书中经常用到的一个重要模块是random。这对于在超级英雄生成器程序中创建我们英雄统计的随机值至关重要,也用于随机选择超级英雄的名字和能力。

要使用它,我们首先必须导入它:

import random

然后将其应用到我们的代码中。例如,我们可以写:

import random

a = random.randint(1, 10)

print(a)

这将在变量a中存储一个 1 到 10 之间的随机值,然后打印出来。

如何用 Python 创建列表、元组和字典

这似乎是一个简单的问题,但是如果程序员不得不当场做的话,这可能会难倒他们,所以练习创建每一个,并知道什么时候使用它们,以便它成为你的第二天性。

答案是:

myList = ['James', 'Mike', 'Spinach Man', 'Mister Kung Food']

myTuple = ('James', 'Mike', 'Spinach Man', 'Mister Kung Food')

myDict = {'Writer' : 'James Payne', 'Student' : 'YourName'}

局部变量和全局变量有什么区别?

局部变量应该在函数中使用;也就是说,我们在函数内部创建变量。如果变量是在函数之外定义的,它就被认为是全局变量。

Python 提供了哪些不同的数据类型?

Python 中总共有五种基本数据类型:数字、字符串、列表、元组和字典。

什么是图形用户界面?什么 Python 库最适合 GUI 开发?

这个由两部分组成的问题有一个简单的答案。首先,GUI 代表图形用户界面,它允许你在程序中加入按钮、标签、文本框、复选框、单选按钮等等。

Python 用于 GUI 开发的默认库被称为 Tkinter。

如何用 Python 打开一个文件?

这是我们在本书中涉及的另一个主题。您可能还记得,我们使用 open()函数打开一个文件。我们首先指定文件的名称和位置(如果文件位于根目录之外),然后指定打开文件的模式。例如:

myFile = open("test.py', 'w')

以写模式打开位于根目录的文件test.py

你如何列出一个模块的功能?

你可能会被问到的另一个常见的面试问题是,如何查看给定模块中的函数列表。为此,我们使用dir()方法:

import random

print dir(random)

使用help()也有助于查看模块中的文档。

其他 Python 面试问题

你永远不知道在面试中你会被问到什么类型的 Python 特有的问题,所以确保你在面试前做了充分的准备。这里包括的问题很常见,但是你可能会被问到更多的问题。

此外,您很可能会被要求回答一些特定于代码的问题,或者被要求编写代码来临时执行一些特定的功能。准备写基础,知道最常见的内置和函数。

准备工作面试的一个很好的方法是研究公司和你将在那里做的节目类型。例如,如果公司开发 web 应用,你提前知道你会被问到关于 web 框架的问题。

最后,随时准备回答与 Python 或编程无关的问题——这些问题也会被问到。在面试过程中,职业目标、过去的经历、性格问题以及总体态度/态度都会被考虑在内,所以一定不要忽视基本的面试准备。

清洁你的耳朵后面…你未来的老板可能会检查他们的背后!

最佳编程实践

虽然大部分编码是个人喜好,但当你进入职场时,总有你必须遵循的标准。我们讨论了良好和适当的文档的重要性;这一部分是关于要遵循的最佳编程实践。

本节中的提示将帮助您成为更好的程序员,使您更高效,避免常见的陷阱,并减少您的编码错误。到目前为止,这还不是一个完整的列表,但是它应该让你像超级英雄一样走上编码之路!

遵循风格指南

在他无限的智慧中,Python 的发明者创造了所谓的风格指南。就像 Python 本身一样,这份风格指南被称为 PEP——或 Python 增强建议——它是 Python 中广泛主题的建议列表。它涵盖了从废弃的(删除的)模块到风格指南,再到语言进化指南的所有内容。

从字面上看,有许多 pep。例如,风格指南是 PEP 8,最初是由我们伟大的领导者 Guido Van Rossum、Barry Warsaw 和 Nick Coghlan 在 2001 年创建的。

它涵盖了如何布局你的代码,是否使用制表符或空格缩进,你的代码的最大行长度,使用字符串引号,等等。

大多数雇佣你的工作都希望你熟悉这个特殊的 PEP,尤其是包含缩进和命名约定的部分。这不仅会帮助你的同事审查和处理你的代码,而且 PEP 风格指南也会帮助你编写更好、更有效和防错的代码。

你可以在 Python 找到 PEP 8。org 网址: www.python.org/dev/peps/pep-0008/

您可以在以下网址找到所有 pep 的列表:

www.python.org/dev/peps/

作为一个例子,下面是 PEP 8 关于命名约定的说明:

类:名称中的第一个和第二个单词(以及任何其他单词)使用大写字母。比如:VillainType或者MutateClass

变量、函数、方法、模块和包:使用由下划线分隔的小写单词。比如:我的 _ 英雄 _ 名或者我的 _ 恶棍 _ 名。

如果它坏了,修好它(现在,而不是以后)

通常,当我们在一个项目上取得很大进展时,我们希望继续向前推进。在办公室环境中尤其如此,当最后期限的压力迫在眉睫,你开始感到时间紧迫,甚至被骚扰以完成你的代码部分并继续下一部分。

然而,这种心态可能会成为一个大问题。虽然我们可能会试图忽略代码中的小错误,并认为我们可以回头修复它们,但事实是,这种思考过程更多的时候是一个陷阱,而不是一种帮助。

这里或那里的错误是意料之中的,但是,就像雪山上的雪崩一样,它们可以很快开始堆积并摧毁它们所经之处的一切。错误往往会导致其他错误,形成多米诺骨牌效应。如果一部分代码不能正常工作或者给你带来错误,它会使其他部分表现异常。更糟糕的是,那些受影响的部分甚至可能不会给出警告或错误,从而导致更大的问题。

这里的教训很简单:经常测试你的代码。如果你发现一个 bug,立即修复它,除非问题得到解决,否则不要继续工作。你以后会感谢我的,相信我!

文档就是一切

我们在书中多次提到这种想法,但在这里值得重复:永远,永远,记录你的代码。清晰的文档是项目成功的关键——这包括其初始版本,以及随后的任何版本。

众所周知,Python 程序可以包含数千行代码。甚至几百万。你读过别人的信件或电子邮件吗?在最好的情况下,人们并不总是清楚的,即使他们和你说同样的语言。Python 也不例外;虽然每个代码(至少应该)都试图坚持传统的命名约定和代码结构,但事实是,许多编码人员都是自学成才的。

随着时间的推移,我们也会变得懒惰和自负;我们假设任何看我们代码的人都会理解我们的意图。更糟糕的是,我们认为我们会记得几年前我们试图做的事情。

虽然记录你的代码可能会多花一点时间,但从长远来看,它会节省你很多时间。不管这样做是因为它减少了你花在追踪 bug 和代码错误上的时间,还是因为你可以快速重用部分代码,文档可能是最重要的——在我的书中(这毕竟是我的书),你可以遵循的最佳实践。

当我们说文档时,它不仅仅包括#注释或“多行注释”;它还包括正确的 docstring 用法。

当你成为一名专业的程序员时,也有一些工具可供你使用,比如 Sphinx 和 reStructuredText。但是现在,从基础开始,练习记录你写的每一段代码。

使用代码库和包

使用 Python 的最大卖点之一是,您可以访问由 Python 开发人员社区创建和测试的庞大的 Python 包库。当您在自己的项目中工作时,这些代码和函数可以为您节省大量的时间、错误和痛苦。俗话说,为什么要重新发明轮子?

您可以在位于 https://pypi.org 的 Python 包索引(PyPi)存储库中找到要使用的包。目前有 155,000 个项目上市,用户近 300,000。

如果您不确定正在寻找什么或正在寻找灵感,您可以搜索项目、浏览项目或查看趋势项目列表。

除了寻找对你的程序有帮助的包之外,你还可以在 PyPi 网站上学习如何打包——以及托管——你自己的包,以便他人测试和使用。

我强烈建议你经常访问这个站点,看看 Python 社区中的其他人都在做些什么。

您可能记得我们在本书中使用 pip 安装了几个包;这是那些包来自的存储库。

经常测试

仅仅因为它需要被重申,我将用另外一段或两段来说:测试你的代码。经常测试。

每当您进行新的重大更改或添加另一部分时,请测试前面的代码。即使是像 if 块或小循环这样简单的事情。如果您有一部分代码依赖于决策或条件语句,请确保测试每个可能的答案。

例如,如果你有一个 if 块,然后说“如果是,那么 X,如果不是,那么 Y,否则 z”,确保你执行这些条件中的每一个。在你的测试中要彻底,如上所述,如果你发现警告或错误,就要修正。

然后,一旦你修复它,再次测试。

选择一边:缩进或空格

这又回到了我们关于风格指南和 PEP 建议的对话;编写代码时,一定要选择是使用空格缩进还是制表符。

那就坚持这个决定。

我亲眼目睹了关于使用哪种方法的争论,最终,我会说这样的话激怒一半的 Python 用户:没关系,只要你始终如一地使用你的选项。

除了个人偏好和 PEP 指导方针,请记住,你工作的任何组织都有自己的风格指导方针,这些指导方针将优先于其他任何东西——个人偏好或其他。

但是同样,在编码时,总是使用相同的间距/制表符约定。

班级很棒,但是并不是所有的事情都需要成为一个班级

任何时候你用 Python 或者任何语言编写任何结构或者东西的时候,总是要考虑它是否是你所做的最好的服务。例如,类在可重用性方面非常好,但函数也是如此。模块也是如此。

说到底,你真正的工作是让一切尽可能简单。如果你这样做了,那么你将会实现我们在本书中多次提到的目标:可重用的代码,减少错误,高效的代码。

保持事物简单的另一个好处是,它使一切更具可读性,这一点的重要性不能被夸大。东西越容易阅读,你和你的同事就越容易追踪问题或添加代码段。

这是使用太多类和模块的负面影响的一部分;虽然它们在许多方面都很棒,但它们往往会破坏 Pythonic 代码的可读性。

使用它们,无论如何;只要确保它们是必要的,并且是最简单的方法来完成你想要达到的目标。

Python 的未来

目前,Python 可以说是这个星球上最常用的编程语言。这一趋势已经持续了相当长一段时间,似乎没有放缓。这种语言简单易学、功能强大且灵活,在可预见的未来,它失宠的可能性非常小。

有几个领域预计会随着 Python 的发展而迅速发展。在某种程度上,这是由于这些特定的利基或行业越来越受欢迎。对于其他人来说,这是因为 Python 在这个领域表现出色。

这方面的一个例子是数据科学、研究和科学编程应用。这种语言在这个领域已经是一个强大的语言,作为数据科学的入门工具,它只会继续发展。

推动 Python 发展的另一个因素是有许多公司基于 Python 2 构建应用。随着 Python 3 的稳定,这些公司开始更新和移植他们的代码到 Python 3,这比换一套全新的代码要简单得多。

当然,Python 并不是无懈可击的。Python 在某些领域确实需要发展。其中之一就是移动开发。然而,不要回避这个领域,你当然可以期待 Python 社区和 Python 创作者挺身而出,确保在移动应用开发和帮助你解决这个领域的工具方面,Python 不会落在后面。

迫在眉睫的——或者现在就敲门,这取决于你在编程研究和技术观点方面的进展——是高科技领域,如人工智能(AI)、虚拟现实(VR)、增强现实(AR)和不断增长的物联网(IoT)领域。智能家居和互联设备是一个快速增长的市场,可以肯定的是 Python 将成为这个市场的一部分。

最终,Python 的学习曲线和易用性使它成为一种在未来几十年将被广泛使用的语言。为什么呢?简单:如果你拥有一家公司,你可以雇佣一个能够快速上手编写 Python 代码的人。结合它的灵活性,社区开发的大量 Python 包,以及我们在本书中讨论的所有其他伟大的东西,我确信 Python 仍然是程序员的发电站。

你也应该如此。

Python 术语

Python 中讨论了很多术语。这本书尽管可能很全面,但并没有涵盖所有的内容。为了帮助总结本书中的数据,并教你一些新的术语,我们包括了这一节来帮助定义一些你作为程序员继续开发时可能会遇到的更常见的 Python 术语。

自变量:你赋给一个函数的值。也称为参数。

赋值:给变量、列表、字典、元组或者其他对象赋值。

布尔:等于TrueFalse的值。

:你可以把一个class想象成一个object的蓝图。有超类——或父类——和子类。子类可以继承父类的特征——方法和属性。使用这些蓝图,你可以基于一个或多个类快速创建对象。

注释:一个comment用来帮助记录——或者解释——一段代码的用途。您可以使用一个#后跟一个空格,然后是一个single-line comment的文本进行注释,如下所示:

# This is a comment.

当 Python 看到#符号时,它会忽略该行空白后面的所有内容,允许您给自己或其他程序员留下注释。如果你需要更多的空间,你可以在后面的每一行注释中继续使用#或者你可以使用'''或者"""进行多行注释。以下是一个多行注释的示例:

'''
Here is a comment.
Here is another.
Here is more!
'''

条件语句:根据是否满足某个条件来决定是否执行的语句。

def : def用于define——或者创建——一个function。更多信息请参见术语函数。

字典:一个dictionary是由一个或多个key-value对组成的数据类型。在这种情况下,每个key对应一个value。字典的关键部分是immutable,意思是不能改变。字典中的值可以是任何类型——数字、字符串或其他类型,并且可以改变。我们这样定义字典:

example_dict{'Name' : 'Paul', 'Age': '22'}

这会给字典分配两个items。第一个键值是Name : Paul,其中Name是键,Paul是值。第二个键是Age,其值为22

docstring :文档字符串;嵌入到 Python 程序、模块或函数中的一段文档。

浮点:十进制数,如 2.5 或 102.19。

函数:一个function是你可以在你的程序中调用的代码。我们通常使用函数来保存我们打算多次使用的代码。

下面是我们如何define一个函数:

def name_of_function(parameters):
      # Here is where your code would go. For example:
      print("Look, I'm a function!")

为了call这个函数,我们可以输入:

name_of_function()

不可变:如果某个东西是immutable,那就意味着你不能改变它的值。

导入:将一个库加载到你的程序中。

整数:整数,比如 1400,20000,甚至-50000。

iterable:aloop的别称。

len :函数len()用于统计一个对象的长度,比如variablelist中的项目等等。如果在列表中使用,它将计算项目或元素的数量。如果用在string上,它会计算字符串中的字符数。以下是一些例子:

a  = "This is my variable"
some_list = [1,2,3,4,5]

len(a)
len(some_list)

这将导致:

19
5

注意

len()也计算空格。

List : Lists是一种 Python 数据类型,存储任意类型的有序值组。与tuples不同,列表是mutable,这意味着它们保存的值可以改变。

要创建列表,您可以键入以下内容:

my_list = [0,1,2,3,4,5]
my_other_list = ['James', 'Super Taco', 'Not So Super Taco', 'Regular Taco Man']

循环:一个loop被用来iterate——或者重复——一段给定的代码,重复的次数取决于一组标准。有一个for循环,无论你告诉它多少次,它都会重复;还有一个while循环,只要条件是TRUE,它就会重复。

一个for循环的例子:

for i in range(0, 5):
      print(i + 1)

这将导致:

1
2
3
4
5

while循环示例:

while a == 4:
      print(" a equals 4! Yay!")

方法:属于一个对象的函数。

可变:某个mutable的东西可以改变它的值。

object :你用一个类的蓝图创建的东西。

参数:参数的另一个名称(尽管有些人会反对这种比较)。

print():print()函数让我们在用户的屏幕上显示或输出一些东西:

print("Hello Universe!")

会导致:

Hello Universe!

字符串:一个string是由任何字母、数字、空白或特殊字符组成的数据类型。

语法错误:当你输入了错误的文本,拼错了一部分代码,或者犯了语法错误时遇到的错误。

回溯:导致错误的函数调用的顺序列表。

元组 : A tuple是一种数据类型,存储任何类型的值的有序集合。与列表不同,它们是不可变的,它们的值不能改变。

您可以使用类似以下代码创建元组:

my_tuple = ('El Taco Diablo', 'Tiny Monster', 'Guy Focal')
my_other_tuple = ('0', '1', '2', '3', '4')

变量 : A variable是存储单个值的数据类型。该值可以是数字、字符、句子等等。它们还可以包含列表、字典,甚至函数。

要创建变量,可以使用赋值运算符:

a = 12
b = "Snap, The Cereal Killer!"

posted @ 2024-08-10 15:28  绝不原创的飞龙  阅读(5)  评论(0编辑  收藏  举报