Python、PyGame 和树莓派游戏开发教程(一)
一、什么是编程语言?
计算机程序是计算机为了完成一项任务而必须执行的一系列语句,这项任务通常是一项重复的任务,需要人类花费很长时间来计算。计算机语言描述这些语句的排列或语法。有各种各样的计算机语言,每一种都适合一个或多个任务。
每种语言都有自己独特的语法和命令集,但它们都有执行大致相同类型操作的结构:
-
投入
-
输出
-
分支(基于数据做出决策)
-
环
命令或关键字是一种特殊的短语,该语言使用它来执行一个动作,无论是从用户那里获得输入还是在屏幕上显示文本。这些命令是保留字,不能在程序中用于任何其他目的。我们将在本书后面更深入地研究它们,但是 Python 中的关键字示例有
-
为
-
如果
-
及格
计算机程序是做什么的?
计算机程序一遍又一遍地执行一系列任务,操纵用户的输入,并在反馈回路中传递输出。当您移动鼠标时(输入),屏幕上的箭头会随之移动(输出)。
计算机程序的旧定义是一个基本的数学公式:
程序=算法+数据
算法是处理数据的一步一步的过程。该算法利用提供给它的数据来解决问题。什么样的问题?它可以是任何东西,从计算一个矩形的面积或一个房间的体积,根据操纵杆的输入将玩家的化身移动到哪里,或者决定敌人应该如何应对刚刚获得电源的玩家。
所有的计算机程序都是以同样的方式编写的吗?对于一个给定的问题,有标准的解决方法吗?嗯,不。不是真的。在计算机编程中有很多方法可以达到同样的效果!没有解决问题的正确方法。只要你的程序做了它应该做的,那就很好!你可能想稍后“调整”你的代码来加速它,但是一旦你有了正确的算法,任何优化都会发生。您的程序必须按预期运行。这是至关重要的。
结论
计算机程序用于对用户输入的一系列数据元素执行繁重的任务。对于游戏来说,这意味着在向玩家显示游戏世界的同时,更新玩家化身的位置并维护游戏世界。
坚持使用一种语言是不明智的,而是要尽可能多的体验多种语言。这将使你,程序员,决定哪种语言最适合给定的情况。你的第一语言是一个很好的选择;Python 是一种非常强大的语言,可以用于各种目的,非常适合第一次编程的人。
二、Python 是什么?
Python 是一种支持面向对象、函数式和命令式编程风格的现代编程语言。因为它的可读性和易用性,它是初学者的理想选择。所有这一切的好处是,与同等的 C/C++或 Java 程序相比,您可以用更少的代码行编写程序。
我刚才到底说了什么?让我们把最后一段分解一下,使它更易读一些。
编程风格
Python 适合以下风格的编程:
-
必要的
-
面向对象
-
功能的
命令式编程在很长一段时间里是编写计算机代码最常见的方式。它一步一步地描述了如何以非常线性的方式对数据进行更改。
例如,我们有以下项目:
-
茶叶袋
-
牛奶
-
杯子
-
匙
-
烧水用水壶
-
水
这些是我们在‘程序’中使用和操纵的东西;这是我们的数据。我们希望将该数据更改为不同的状态。什么州?嗯,我们想要一杯奶茶。我们如何做到这一点?我们规定了一系列操作,将这些数据转换成其他数据,如下所示:
-
将茶包放入杯中
-
将水倒入水壶
-
烧开水壶
-
当水壶烧开的时候,看电视
-
把水壶里的水倒到杯子里
-
把牛奶倒进杯子里
-
用勺子搅拌茶
-
服务
在代码中(不特别是 Python 代码),这可以写成
addTo(cup, tea_bag)
addTo(kettle, water)
boil(kettle)
while isBoiling(kettle):
watchTV()
addTo(cup, getWaterFrom(kettle))
addTo(cup, milk)
stir(cup)
serve(cup)
这些是改变我们的初始数据(我们的输入)并将其转换为我们的输出的规定步骤(过程)。见图 2-1 。
图 2-1。
输入、过程、输出框图
面向对象
命令式程序将功能(算法)与数据分开。面向对象语言保留了数据的功能。对象在一个地方包含数据和用于操作该数据的指令。
这是有好处的;它存储的算法处理你的数据。让我们以一支铅笔为例。它有一些描述它的属性:
-
颜色
-
困难
-
笔尖尺寸
-
长度
它还具有可以应用于它的某些操作或方法:
-
写
-
抹去
-
尖锐
这些方法改变对象的状态;记住状态是由数据决定的。例如,当你用铅笔写字时,笔尖的长度会越来越短。当您削尖铅笔时,它的总长度会变短,但笔尖大小会重置为最大值。
功能的
函数式编程并不新鲜,最早是在 20 世纪 30 年代开发的。它源于λ微积分。函数式编程使用数学函数来执行计算。这些计算中没有数据发生变化;而是计算新值。这意味着函数式程序没有状态。
函数式编程倾向于用于递归(从自身调用同一个函数)和项目迭代。
在 Python 中,可以用下面一行代码计算斐波那契数:
fib = lambda n: n if n < 2 else fib(n-1) + fib(n-2)
这摘自一篇关于 StackOverflow ( http://bit.ly/FibonacciPython )的讨论。
要计算一个值,程序员只需传入一个整数值:
fib(5)
Pygame 是什么?
Pygame 是由 Pete Shinners 作为一个简单的 DirectMedia 库(SDL)的包装器开始的。它自 2000 年以来一直由社区维护,并在 GNU 宽松通用公共许可证下发布。这意味着如果你愿意,你可以随意查看源代码。
Pygame 的创建是为了允许在不使用 C 或 C++等编程语言的情况下开发游戏。
Pygame 可以用来编写复古风格的快节奏 2D 游戏,或者现代休闲和超休闲游戏。它处理加载图像、显示精灵、播放声音等困难。,给你的。
更多关于 Pygame 的细节,请访问他们的网站: www.pygame.org/news 。
结论
Python 是一种现代的多参数编程语言。它可用于命令式、面向对象和函数式编程。
此外,Pygame 是一个允许你在 2D 创建快节奏动作游戏的框架。
所以,现在我们知道了 Python 的能力,是时候看看语言本身了。
三、Python 简介
本章我们将介绍 Python 语言。在这个阶段,我们只对理解 Python 语言及其关键字的格式或语法感兴趣。Python 是一种解释型语言,这意味着它需要另一个叫做解释器的程序来运行我们编写的任何代码。
Python 解释器程序叫做 Python,是一个可执行程序。当您从命令行单独运行 Python 时,您将看到以下内容:
pi@raspberrypi ∼ $ python
Python 2.7.9 (default, Jan 13 2013, 11:20:46)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more info
>>>
这是 Python 解释器,将在您键入命令时运行每个命令块。
终端窗口
对于我们的前几个 Python 实验,我们将使用 Raspbian 中的终端窗口。要打开终端窗口,请点按屏幕左上角看起来有点像> _ 的图标。这将打开一个带有如下文本的窗口:
pi@raspberrypi:~ $
这是一个非常友好的提示,因为计算机正在告诉一些重要的信息。它显示您作为(pi@raspberrypi)登录,以及您在目录结构中的位置。在这种情况下,它是~它是您的主目录的简写。
该文本的右侧是光标。这是您键入的文本将出现的地方。
运行 Python 解释器
要启动 Python 解释器,请在终端窗口中键入以下内容:
$ python
Python 中的命令块是至少一行长的命令列表。现在让我们试一试:
print 'Hello, world!'
这将指示 Python 显示短语“Hello,world!”屏幕上。注意 Python 没有显示引号:
Hello, world!
这是因为‘你好,世界!’是字符串文字。字符串是包含字母数字或符号字符的任何短语,括在“和”或“和”之间。你不能混淆和匹配报价。能够同时使用这两者有时会变得非常方便。
让我们试试这个:
print "It's going to rain on Saturday."
使用双引号来标记字符串文字的开始和结束位置,我们可以使用单引号作为撇号:
It's going to rain on Saturday.
如果我们使用单引号,我们将不得不在行中添加一个特殊的转义字符:
print 'It\'s going to rain on Saturday.'
我们稍后会对字符进行转义,但是如果只是想在句子中放一个撇号,那就有点麻烦了!
让我们来分解一下我们刚刚使用的打印语句。print 是 Python 用来将信息输出到屏幕的关键字。第二部分,字符串文字,是 print 命令的参数。参数也称为自变量。
Python 被解读
Python 的每一行都有解释。这意味着计算机接受您键入的每一行代码,并一次一行地将其转换为计算机可以理解的代码。另一种类型的语言是编译语言。当一种语言需要编译来把你的源代码翻译成计算机能理解的语言时,这个过程是由另一个叫做编译器的程序来完成的。这是一个单独的程序,在你写完所有代码后运行。
因为 Python 语言是解释型的,所以运行它只需要一个程序:Python。当我们在交互式 Python shell 中时,我们输入的任何内容都会立即被程序解释,如果有结果的话,结果会显示在屏幕上。
作为计算器的 Python
假设我们想把两个数加在一起,为了便于讨论,2 和 2。在 Python 解释器中键入以下内容,然后按 return 键:
2+2
您将在屏幕上看到的是您(希望)期望看到的内容:
4
我们将在后面看到所有的算术运算(加、减、乘、除)都是可用的,还有一些你以前可能没见过的。他们会在你阅读课文时被介绍。
示例:
5 * 4
10 / 2
7 + 2
9 - 4
更复杂的东西呢,比如
2 + 2 * 6
你期望看到什么?24?为什么是 14?那是因为算术运算符是按优先顺序工作的,或者换句话说,有些运算符比其他运算符更重要。乘法运算符“*”和除法运算符“/”比分别用于加法和减法的+和–更重要。
如果你想保证操作的顺序,你可以像这样使用括号'('和')':
(2 + 2) * 6
其现在将给出 24,因为将首先执行 2 和 2 的相加,然后其乘积将乘以 6。注意你的括号!确保它们匹配。如果不这样做,您将得到一个延续标记'…'),如下所示:
>>> (2 + 2 * 6
...
假设您想以米为单位计算地板的面积(宽×长),并将该值转换为平方英尺。假设这个房间长 2 米,宽 4 米。您可以使用类似于
(2 * 4) * (3.28 * 3.28)
这是因为一米有 3.28 英尺;为了得到一平方米的英尺数,我们将 3.28 英尺乘以它本身,得到 10.7584。乘以 2 * 4 得到
86.0672
或者大约 86 平方英尺。
我们稍后将深入讨论这一点,但是现在我们应该花点时间来讨论到目前为止已经输入了什么。
您输入的数值称为常数。他们永远不会改变。1 永远是 1,24.234 永远是 24.234。为了安全起见,我们可以将常量存储在内存中,以便以后在程序中引用它们。计算机内存中的这些槽叫做变量。之所以这么叫,是因为我们存储的值会随着程序的进行而变化。假设我们想要存储常数 10.76。我们必须给它起个名字。此操作称为变量赋值,如下所示:
squareFeet = 10.76
你可以理解为“给平方英尺赋值 10.76”或者“给平方英尺赋值 10.76”,或者(我喜欢这样称呼)“平方英尺等于 10.76。”这更像是一种“说出你所看到的心态”!
任何时候我们想要使用这个变量,我们使用它的方式和使用一个常量是一样的。计算那个 2 × 4 米的房间的面积
(2 * 4) * squareFeet
Python 是区分大小写的!请注意,变量的名称是“平方英尺”,而不是“平方英尺”或“平方英尺”
关键词
Python 内置的关键字非常少,总共 31 个。从这些我们可以制作任何你想制作的程序,从简单的球棒和球游戏到电子表格应用,如果你想制作其中一个的话。Python 的关键字如下:
-
和
-
如同
-
维护
-
破裂
-
班级
-
继续
-
极好的
-
是吗
-
艾列弗
-
其他
-
除...之外
-
高级管理人员
-
最后
-
为
-
从
-
全球的
-
如果
-
进口
-
在
-
存在
-
希腊字母的第 11 个
-
不
-
或者
-
及格
-
打印
-
上升
-
返回
-
尝试
-
正在…
-
随着
-
产量
这些是语言的组成部分,如果你喜欢的话,是乐高积木。从所有这些词你可以创造任何东西,从简单的计算到游戏到应用软件。有时,大部分真正困难的工作已经为您完成,并以 Python 模块的形式提供。这是一个命令、例程和对象的库,它们打包在一起提供一个通用的功能。PyGame 是一个模块集合的例子。PyGame 中的每个模块都提供了预先编写的代码,可以在屏幕上绘制图像,从玩家那里获得输入,或者播放背景音乐,从而使程序员制作游戏变得更加容易。
印刷
我们已经看到了如何在屏幕上显示简单的结果,但是您可以对这些消息的格式(它们看起来是什么样子)有更多的了解。例如,您可以使用转义序列添加空白字符,如制表符,并使用 print 命令返回到文本。例如:
print("these\nare\non\nseparate\nlines")
print("tab over\tto here")
反斜杠字符“\”用于为下一个字符生成“转义”代码。转义字符或控制序列可以追溯到电传时代,用于控制我们正在打印的设备的输出:在这种情况下是屏幕。
有各种控制序列,这些序列及其描述在表 3-1 中列出。
表 3-1。
控制序列
|换码顺序
|
描述
| | --- | --- | | \ | 输出反斜杠 | | ' | 输出单引号(') | | " | 输出双引号(") | | \a | 铃 | | \b | 执行退格 | | \f | 执行换页 | | \n | 执行换行 | | \N(姓名) | UNICODE 数据库中的字符命名名称 | | \r | 执行回车 | | \t | 执行水平定位 | | \ uxxx | 具有 16 位十六进制值 xxxx 的字符 | | \Uxxxxxxxx | 具有 32 位十六进制值 xxxxxxxx 的字符 | | \v | 执行垂直制表符 | | \ooo | 八进制值为 ooo 的字符 | | \xhh | 十六进制值为 hh 的字符 |
从这些转义字符中,您可以创建复杂的输出。这可用于显示表格信息,例如:
print("Team\t\tWon\tLost\nLeafs\t\t1\t1\nSabres\t\t0\t2")
将显示下表:
Team Won Lost
Leafs 1 1
Sabres 0 2
这很好,但是如果我们想做得更好呢?假设我们想将数字右对齐而不是左对齐?这意味着将数字移动到与“赢”和“输”的最后一个字符相同的列这就是字符串格式发挥作用的地方。
字符串格式
字符串格式允许您决定信息如何以文本形式显示给用户。我们已经看到了如何通过决定文本放置的位置来操纵文本的可视部分;我们现在将研究数据如何呈现给用户。我们不需要改变数据:我们只是改变用户查看数据的方式。
通过在文本中为要插入的信息使用占位符来实现格式化。这些如表 3-2 所示。
表 3-2。
字符串格式占位符
|占位符
|
描述
| | --- | --- | | %s | 线 | | %d | 整数 | | %f | 浮点数 | | %r | 原始值 |
原始值对于程序的最终用户来说不是特别有用,但是当您调试代码试图找出错误时,它会很方便。在调试章节的后面会有更多的内容。
如果我们想要显示三个数字,例如,一个对象的 x、y 和 z 坐标,那么我们可以使用类似
print("{%d, %d, %d}" % (1, 2, 3))
字符串文字中的“%”表示下面的项是占位符,并且是整数的“d”类型。字符串文字外的“%”用来表示“用'填充那些占位符”,然后括号中的最后一位'('和')'称为元组。这些值按照出现的顺序放在字符串中。输入该行时出现的文本是
{1, 2, 3}
让我们再试一次,但这次是玩家的名字、分数和完成百分比:
print("%s scored %d and completed %f of the quest" % ('Sloan', 15, 55))
这将输出
Sloan scored 15 and completed 55.000000 of the quest
您会注意到输出有点过了;浮点数显示了很多零。我们可以通过指定小数点右边应该有多少个点来最小化这个问题。
让我们将该行改为只显示两个小数点:
print("%s scored %d and completed %.2f of the quest" % ('Sloan', 15, 55))
现在该语句的输出是
Sloan scored 15 and completed 55.00 of the quest
我们还可以使用“%”符号后的数字来分隔值。例如:
print("%20s%20d" % ('Sloan', 15))
这将在宽度为 20 的列中显示值“Sloan”和“15 ”:
Sloan 15
这些值与它们的位置右对齐,它们都占据 20 列。如果我们想让玩家的名字靠左对齐呢?我们将使用负值:
print("%-20s%20d" % ('Sloan', 15))
通过使用负值,您指定需要 20 个空格,但文本必须靠左对齐:
Sloan 15
回到曲棍球队的例子,我们现在可以使用这些信息来更好地放置文本和数据。我们可以让表格使用固定值,而不是依赖于根据文本大小而变化的制表符,如下所示:
print("%s%s%s\n%s%d%d\n%s%d%d" % ('Team', 'Won', 'Lost', 'Leafs',1,1,'Sabres',0,2))
这显示了占位符前面没有值时的显示方式。现在每个项目的列宽为:
print("%-10s%10s%10s\n%-10s%10d%10d\n%-10s%10d%10d" % ('Team', 'Won', 'Lost', 'Leafs',1,1,'Sabres',0,2))
这么多“%”符号,不是吗!这是一个相当严重的案例,而且不是一个特别常见的案例。事实上,你可以用一种叫做变量赋值的东西来使它更容易阅读。我们现在将详细讨论这一点。
变量
当我们处理数据时,变量被用来在内存中存储数据。我们使用名字来访问数据。每个变量都可以赋值。这个值代表我们想要处理的数据。假设我们想存储玩家的名字,以便以后可以检索。
这叫做变量赋值。当我们给一个名字赋值时,我们说这个名字现在包含了赋值:
>>> player = 'Sloan'
>>> print(player)
Sloan
>>>
我们的变量赋值是
player='Sloan'
等号(=)的左边是名称,等号的右边是值。该值可以是字符串、整数或浮点数,也可以是复杂的数学公式。
命名变量
你可以随意称呼变量,但是我建议它们反映你期望存储在其中的数据。对于可以用作名字的字符,有几个注意事项。它们可以是字母数字字符,可以包含下划线字符(_),但名称不能以数字开头。您还应该小心以下划线字符开头的名称,因为这有时用于 Python 本身使用的内部名称,以及稍后将讨论的其他特殊情况。
这些是有效的变量名:
playerName
player1
numOfLives
_arg1
this_is_a_long_name_hope_its_worth__it__555
这些是无效的变量名。给出的理由显示在“#”的右边。“#”在 Python 中用作注释字符。一行中“#”后面的所有内容都被忽略:
123Fred # starts with a number
Fr*d # contains an illegal character '*'
player$ # contains an illegal character '$'
the Player # contains a space. Spaces are not allowed
Python 变量名区分大小写!小心:
thisVariable
不等同于
Thisvariable
你被警告了!小心你的箱子!
PYTHON 是区分大小写的!
Python 作为计算器,第二部分
请记住,计算机程序从用户那里获取信息,对其进行处理,并作为输出反馈给用户。在本节中,我们将把 Python 变成一个计算器。假设我们将一罐汽水的价格设定为 55 美分,让我们记住将值 55 放入变量中:
canOfSoda = .55
我们可以用这个变量名来回忆一罐汽水的价格。现在,假设我们被告知购买 12 罐汽水,让我们在另一个变量中也记住这一点:
numCans = 12
我们现在可以用一个简单的公式打印出 12 罐汽水的价值:
canOfSoda * numCans
但是等等!这是什么?!你不会得到 6.6 分,你会得到这个:
6.6000000000000005
这似乎有点奇怪,不是吗?为什么会发生这种情况?这都与精度有关。当计算机计算分数时,它们必须使用二进制数(以 2、0 或 1 为基数)来计算这些分数。当把它们转换回十进制值时,就不太对了。我们可以使用字符串格式自己整理它:
"%2.2f" % (canOfSoda * numCans)
那更好!我们可以进一步整理它,以显示美元(或当地货币符号)金额:
"$%2.2f" % (canOfSoda * numCans)
这将显示
'$6.60'
请注意,我们的值周围有' ';这是因为我们对 Python 终端进行原始输出,所以我们输入的任何内容都会立即得到处理和输出。如果我们想打印出不带引号的字符串,我们需要添加 print 命令:
print("$%2.2f" % (canOfSoda * numCans))
产出:
$6.60
然而坏消息是,一罐汽水的价格已经涨到了 70 美分。不过没问题,因为我们可以告诉 Python 记住新值:
canOfSoda = .7
现在当我们计算 12 罐汽水时,我们会得到一个新的值。
以下进程的输出显示以前的值、赋值和新值:
>>> canOfSoda
0.55
>>> canOfSoda = .7
>>> canOfSoda
0.7
>>>
如果我们想知道一打罐头的价格,我们使用和以前一样的行:
print("$%2.2f" % (canOfSoda * numCans))
您知道吗,您可以使用键盘上的上下光标(箭头)键在交互式 Python 程序中输入的 Python 语句的历史中向前或向后移动。当您单步执行语句时,您可以使用左右光标键沿行移动,使用 delete/backspace 键删除不需要的字符。可以节省你一些打字时间!
算术运算符
算术运算符是用于对数字执行算术运算的缩写符号。你在学校里会用到它们中的大多数;Python 使用了一些与学校使用的符号不同的符号(表 3-3 )。
表 3-3。
Python 算术运算符
|操作员
|
描述
|
例子
| | --- | --- | --- | | + | 加法;运算符两边的两个值相加在一起 | 4 + 5 等于 9 | | - | 减法;运算符右侧的值从左侧的值中减去 | 5–4 等于 1 | | ***** | 乘法;运算符两边的两个值相乘 | 2 × 3 等于 6 | | / | 司;将运算符左侧的值除以右侧的值 | 10 / 5 等于 2 | | % | 模数;将运算符左侧的值除以右侧的值,得到余数 | 5 / 2 等于 1 | | ****** | 指数;通过右侧提供的电源提高左侧的值 | 2 ** 4 会给 16。这在数学上写为 24 或 2 * 2 * 2 * 2 | | / | 楼层划分;将运算符左侧的值除以右侧的值,得到整数的下限值 | 5 / 2 将给出 2.0 |
数据类型
Python 使用了一种叫做鸭子类型的东西。Duck typing 确保了只要特定命名值(变量)的方法或功能存在,Python 就会对其执行该操作。诗人詹姆斯·惠特科姆·莱利想出了这个短语来描述归纳推理:
如果它看起来像鸭子,游泳像鸭子,叫声像鸭子,那么它很可能就是一只鸭子。
Python 也有特定的数据类型,这些数据类型用于描述变量的内容。Python 具有以下内置数据类型:
-
数字
-
顺序
-
绘图
-
文件
-
班级
-
例子
-
例外
数字类型
Python 中的数字可以用整数或分数来表示。整数被称为整数,它们没有分数部分,如-256,–5,1,5,9,17,2048。分数有一个小数点和小数点后的一些值,例如 0.5、0.333、–0.1。
整数由两种数据类型表示:“int”是 integer 的缩写,“long”是 long。分数用“float”表示还有一种叫做“复数”的数字,我们在游戏中不会用到,但是 Python 可以处理它。
数字数据类型在表 3-4 中有详细描述。
表 3-4。
数字数据类型
|数字类型
|
描述
| | --- | --- | | int | 整数的大小至少为 32 位(4 字节),这意味着您可以存储任何整数,最大为 4,294,967,295,包括 4,294,967,295。但是,这通常是一个有符号的值,这意味着值的范围实际上是从–2,147,483,648 到+2,147,483,647。 | | 浮动 | 浮点数是具有小数部分的数字,如 2.4 或 1.49387。 | | 龙 | 长整数的精度没有限制,因此可以用来存储它们的位数没有上限。 | | 复杂 | 复数有实部和虚部。这些部分是浮点数。 |
此外,表 3-5 中所示的运算符可能会派上用场。这些在日常算术中并不使用,但是你可能想求一个值的反,或者把它从整数转换成浮点,反之亦然。
表 3-5。
附加运算符
|操作员
|
描述
|
例子
| | --- | --- | --- | | –x | 对值“x”求反 | –2 给–2 | | +x | 保持值“x”不变 | +2 等于 2 | | abs(x) | “x”的绝对值 | ABS(–5)给出 5 | | int(x) | 将“x”转换为整数 | int(5.44)得出 5 | | long(x) | 将“x”转换为整数 | long(5)给出 5 | | 浮动(x) | 将“x”转换为整数 | float(5)给出 5.0 | | 复数(实数,虚数) | 用实部“real”和虚部“imaginary”创建一个复数 | 复数(1,5)给出(1+5j) |
例如,要计算长 5 米、高 10 米的建筑物侧面的面积:
width = 5
height = 10
area = width * height
要显示该值,请键入
area
这将显示 5 × 10 的答案:
50
再次字符串格式化
让我们回到曲棍球比分表:
print("%-10s%10s%10s\n%-10s%10d%10d\n%-10s%10d%10d" % ('Team', 'Won', 'Lost', 'Leafs',1,1,'Sabres',0,2))
我们可以将它分解成更小、更易读的数据块。不要害怕这样做;让你的程序可读性比速度更好。你应该努力使代码正确,而不是快速。优化可以以后再来。
让你的代码可读!当你以后再看它的时候,你仍然能够理解它!
表格中使用了通用格式;每个队都有十个字符作为他们的名字和输赢号码。每一行的末尾都有一个新的字符。我们可以设置一个变量来记住这种格式:
formatter="%-10s%10s%10s\n"
然后,只需为每个标题和团队分配使用这种格式的变量:
header=formatter % ("Team", "Won", "Lost")
leafs=formatter % ("Leafs", 1, 1)
sabres=formatter % ("Sabres", 0, 2)
现在我们已经将标题和团队数据存储在变量中,我们可以将它们组合在一行中来绘制我们的表格:
print("%s%s%s" % (header, leafs, sabres))
如果我们愿意,我们可以把它赋给一个变量,然后打印出来。我们的变量赋值如下所示:
table = "%s%s%s" % (header, leafs, sabres)
如果我们只是在 Python 解释器程序中输入表格,我们会得到如下显示:
'Team Won Lost\nLeafs 1 1\nSabres 0 2\n'
这是 name 表内容的原始输出。这向我们显示了名称表包含的内容,但不是它将如何显示。要正确显示表格
print(table)
将显示
Team Won Lost
Leafs 1 1
Sabres 0 2
结论
通过在终端窗口中输入 python,可以通过 Python 解释器交互式地使用 Python。虽然这对于一次性计算和简单的文本输出很方便,但我们现在将通过使用文本编辑器之类的工具创建实际的程序来更深入地研究 Python 的世界。
四、从解释器挣脱出来
到目前为止,我们一直使用解释器来编写代码。当输入每一行时,Python 程序会对其进行解释,处理后的行输出会显示在屏幕上。从现在起我们将使用闲置。
要退出解释器,如果您还没有这样做,请按 Ctrl+D 或输入 quit()。保持终端窗口打开!我们很快就会需要它。
什么是闲?
在本书中,我们将使用集成开发环境(IDE ),它包含在 Raspbian IDLE 中,是集成开发和学习环境的缩写。
起动怠速
要启动 IDLE,点击 Raspberry Pi logo,打开“编程”入口,点击“Python 3 (IDLE)”。Python shell 将在一个新窗口中打开,如图 4-1 所示。
图 4-1。
启动空闲 IDE
开始一个新文件
要创建新文件,请单击文件➤新建文件或按键盘上的 Ctrl+N(图 4-2 )。
图 4-2。
从“文件”菜单中选择“新建文件”,创建一个新的编辑器窗口
这将打开一个新的文本编辑器窗口,我们可以输入组成我们程序的代码(图 4-3 )。
图 4-3。
将用于编写 Python 程序的空白编辑器窗口
这是一个好主意,组织你的工作,并知道在哪里可以很容易地找到它。这里将展示一些基本的项目管理。我们将首先在当前用户的主目录(通常是/home/pi)中创建一个文件夹,并将这个新文件夹命名为“pygamebook”(不带引号)。我们会把我们写的所有程序放在这个文件夹里。我们可以为每个项目创建子文件夹,但是“pygamebook”是我们的主文件夹。
在终端窗口/命令提示符下,输入以下命令,在每一行后按 enter 键创建 pygamebook 文件夹:
$ cd
$ mkdir pygamebook
第一行将确保在您的主目录(~)中创建“pygamebook”文件夹。第二行创建了一个名为“pygamebook”的目录(mkdir 是“make directory”的缩写)。使用此文件夹将您从本书创建的所有文件放在一起。
你好,世界!
大多数人编写的第一个计算机程序是显示“你好,世界!”信息的程序在屏幕上。这本书也不会有什么不同!在下面的空白窗口中键入代码,每一行都是我们进行的描述。
任何 Python 脚本文件的第一行都是 Python 解释器的位置。这被称为 hash-bang,看起来像这样:
#!/usr/bin/python
所有程序都由外壳运行。这是计算机操作系统的一部分,控制程序对内存、磁盘驱动器等资源的访问。
因为源文件只是文本文件,所以这个 hash-bang 让 shell 知道它是一个应该由位于/usr/bin/python 的 Python 解释器运行的脚本。
现在我们已经准备好了,我们可以开始我们的程序了。在这种情况下,它非常简单;我们标准的“你好,世界!”程序:
print("Hello, World!")
现在,编辑器窗口中应该有以下几行:
#!/usr/bin/python
print("Hello, World!")
通过单击文件➤保存或按键盘上的 Ctrl+S 来保存文件。出现提示时,将文件另存为“hello.py”(不带引号),保存到我们之前创建的“pygamebook”文件夹中。
从命令行运行
如果您想从命令提示符运行您的程序,您将不得不再执行一个步骤。默认情况下,Raspbian 不使文件可执行;我们必须这么做。在终端窗口中,移动到“pygamebook”文件夹,并使用 chmod 命令使程序可执行。以下命令序列将完成此操作:
$ cd
$ cd pygamebook
$ chmod +x hello.py
这将可执行标志添加到文件的属性中。没有这个属性,操作系统将无法运行我们的程序。要在终端窗口中运行程序,请键入
每个脚本只需添加一次可执行标志属性!
$ ./hello.py
为什么我们要加上。/'?这是因为在 Raspbian 中,可执行文件是通过一系列路径来搜索的。我们的新文件夹不是系统路径的一部分,所以我们必须告诉它它在哪里。幸运的是,这有一个捷径;当前目录名为“.”
如果您愿意,可以省略这一步;事实上,只有当您像前面显示的那样单独运行程序时,才需要 hash-bang 行。如果省略该行,Raspbian shell 不知道使用什么程序来运行脚本。在这种情况下,您可以使用
$ python hello.py
这将启动 python 并运行“hello.py”脚本(图 4-4 )。
图 4-4。
添加可执行属性并从命令行运行 hello.py
从内部空闲运行
要在空闲状态下运行程序,按键盘上的 F5 键或点击菜单中的运行➤运行模块(图 4-5 )。
图 4-5。
通过从运行菜单中选择运行模块或按键盘上的 F5 来运行程序
当程序运行时,你应该看到“你好,世界!”显示在窗口中(图 4-6 )。
图 4-6。
在空闲的内部运行 hello.py
从现在开始,在本文中,这本书将专注于为我们的 Python 程序编写脚本文件,而不是像我们在前几章那样使用 Python 解释器。
当创建一个将从命令行运行的 PYTHON 脚本文件时,总是将解释器的路径作为第一行放在 HASH-BANG: #!/usr/bin/python
在很大程度上,我将从示例程序中省略这一行,并假设我们将从 IDLE 中运行或用 python 启动我们的程序。
结论
Raspbian 包括一个名为 IDLE 的 Python IDE,可以用来编辑和运行 Python 程序,而不需要使用终端窗口。您仍然可以在终端窗口中运行使用 IDLE 创建的 Python 脚本,只需确保添加了 hash-bang 行来显示在执行该脚本时应该运行什么 Python 解释器程序。
在整篇文章中,我将交替使用脚本和程序。脚本是一个文本文件,由程序解释以执行其中的指令。程序是类似的,但它通常(但不总是)被编译成机器代码。由于这些相似性,我不打算在本文中吹毛求疵地谈论 Python 源文件是被称为程序还是脚本。
五、做决策
到目前为止,我们已经看到了非常线性的程序。这些程序从一个语句到下一个语句,从不偏离。它们只是一个线性购物清单。你先吃蔬菜,然后是面包,然后是蔬菜罐头,最后是猫粮。为什么呢?因为这是超市里这些商品通常出现的顺序。
但是如果你想做简单的改变呢?如果你的程序可以根据输入决定做什么,那会怎么样?
在计算机科学中,这被称为分支。本质上,决策是基于给定的数据做出的,一个代码块在另一个代码块上执行。让我们来看一下图 5-1 中的一张图。
图 5-1。
显示简单“if”语句的流程图
这被称为流程图,它显示了根据我们的输入做出的一系列决策所采用的路线(流程),我们使用这些输入来生成我们的输出。在图中,我们在问一个问题:“下雨了吗?”我们的数据要么是“是”,要么是“否”。如果问题的答案是“是”,那么我们就带一把雨伞。否则呢?我们什么都不做。
计算机在这些类型的决策方面非常出色;要么是,要么不是;开或关;真或假。
事实上,计算机只真正理解这些二元决策。
二进制意味着某物不是开就是关,是真还是假。
在 Python 中,我们没有“是”或“否”的值,但我们确实有类似的值;“真”和“假”这分别是“开”和“关”的值。那么我们如何用 Python 写这个呢?我们使用“如果”关键字。在英语中,我们会说,“如果下雨,我会带雨伞”;在 Python 中,写为
isRaining = True
if isRaining:
print("I will take my umbrella to work today")
第一行将常量“True”赋给“isRaining”True 是一个特殊的关键字(和 False 一起),在 Python 中用来表示布尔测试的结果。
第二行检查包含在“isRaining”中的值,如果它被设置为 True(确实如此),它将打印出文本字符串。请注意,您必须在 print 语句开始时按 tab 键。这是因为它构成了“isRaining”为真时将执行的语句列表。在这种情况下,我们有一个语句,但是如果我们有更多的语句要执行,如果' isRaining '为真,它们都将使用 tab 键缩进。
如果条件总是等于两个值之一:真或假。
我们也可以将“如果”语句写成
if isRaining == True:
这要清楚得多,但不是首选的用法。当你有一个以“is”或“has”开头的变量时,假设它包含一个布尔值。永远!永远!–在使用变量之前,请检查情况是否如此。
“if”语句的格式是
if condition: {statement}
或者
if condition: {block}
第二种方法是首选,因为您可能希望返回并向要在“if”块中执行的代码添加更多行。并不是说对于块中的每一行,每次都要缩进相同的量。
关于块的一个注记
代码块是一行或多行 Python 代码。例如,当包含在控制语句(如“if”、“for”或“while”)中时,组成块的语句必须移动一个制表符。这是因为 Python 不使用语法糖或额外的字符来表示块的开始和结束。基于 C 语言的语言使用“{”和“}”来表示块。Python 没有。例如见图 5-2;这是 Python 版本旁边的 C 语言风格的等价物。
图 5-2。
展示了显式块字符和 Python 的隐式缩进方法之间的区别
我们还可以在“:”后放置多行,如下例所示:
isSunny = True
if isSunny:
print("It is sunny outside")
print("I won't need my umbrella")
只有当“isSunny”为“True”时,才会执行“if”块中的两行如果我们想展示一些东西,如果训练不是真的呢?我们能这样做吗:
isRaining = True
if isRaining:
print("I will take my umbrella to work today")
print("It is nice and sunny")
该程序运行时会显示以下输出:
I will take my umbrella to work today.
It is nice and sunny
这不是理想的情况,因为我们只希望输出一行。第二行总是会被执行,因为正如我们所知,程序盲目地一步一步运行,直到程序结束,没有其他行需要处理。我们需要做的是:
isRaining = True
if isRaining:
print("I will take my umbrella to work today")
else:
print("It is nice and sunny")
请注意额外的关键字“else”。这使我们能够更好地控制如果“正在训练”被证明是错误的,我们期望做什么。你不必为每个“如果”加上一个“否则”有时没有其他选择,您只想针对特定条件运行一组特定的语句。
相等性测试
Python 允许程序员测试相等性——在我们测试特定变量等于 true 时,我们已经看到了这一点。我们知道,如果条件必须等于两个值之一:真或假,那么我们如何测试(不)相等呢?我们使用以下范围运算符之一:
-
等于(==)
-
小于(
-
大于(>)
-
小于或等于(< =)
-
大于或等于(> =)
-
不等于(!=)
这些是数学符号。对于那些不熟悉它们的人来说,尤其是小于和大于符号,小尖点表示较小的值。不能对包含布尔值 True 或 False 的变量使用这些运算符;相等运算符只能处理数字或字符串。
下面的程序提示用户输入两个字符串值,然后检查哪个字符串更大。我们将在一秒钟内讨论更好的细节,但是这个程序确实有一些缺点。你能看出它们是什么吗?
打印“这个程序将接受两个字符串,并决定哪一个更大”
first = input("First string: ")
second = input("Second string: ")
if first > second:
tup = (first, second)
else:
tup = (second, first)
print("%s is greater than %s" % tup)
第一行显示一条消息,指示程序将做什么。接下来的两行提示用户输入两个单独的字符串值,并将它们放在“第一”和“第二”变量中。“if”语句的条件是
if first > second:
这将检查第一个字符串是否大于第二个字符串。如果是,则创建一个称为“tup”的元组,并存储第一个和第二个元组。注意顺序;第一是在第二之前。我们将在后面详细讨论元组,但现在让我们假设它们是一个或多个值的集合。
如果第二个字符串大于第一个字符串,那么也创建 tup 变量,但是顺序相反;“第二个”出现在“第一个”之前
键入前面的程序并运行它。在表 5-1 中输入数值。
表 5-1。
两个字符串程序的值
|程序运行次数
|
第一
|
第二
| | --- | --- | --- | | 1 | 小写 a | 大写 A | | 2 | 美国汽车协会 | 打鼾声 | | 3 | nine | One hundred |
你对结果有什么注意?你料到了吗?
我们这个小例子的问题是,除非‘first’绝对大于‘second’,否则执行‘else’块。我们可以通过将程序改为
print("This program will take two strings and decide which one is greater")
tup = None
first = input("First string: ")
second = input("Second string: ")
if first > second:
tup = (first, second)
elif second > first:
tup = (second, first)
if tup != None:
print("%s is greater than %s" % tup)
else:
print("The strings were equal")
关键字“None”用于初始为“tup”赋值无意味着没有给变量赋值。我们仍然希望有一个名为' tup '的变量,并在以后给它赋值。因此,在这种情况下,我们最初将“tup”设置为等于“None ”,因为在程序的逻辑中可能根本不会设置它。如果我们不设置它,那么试图访问它将导致“未定义”错误。
如果你看到一个“name 'variable name' not defined”的错误,这通常意味着你在使用它之前没有给它赋值,或者你拼错了变量名!
更改前面的程序,在第二个“if”中使用等号(==)您需要更改“打印”声明的文本吗?如果是,你会把它们换成什么?
比文本相等更常见的是数字相等。数字相等测试用于碰撞检测,决定玩家或敌人是否死亡,还有多少燃料,等等。
比方说,我们想要检查玩家的角色是否在屏幕上的某个边界内。这包括检查玩家的 x 和 y 坐标。我们可以使用布尔逻辑在一个语句中组合我们的条件。
在这个例子中,我们测试玩家的 x 和 y 坐标,以确定他们是否在一个矩形区域内,该区域宽 100 个单位,高 225 个单位,位置在(0,25)处,如图 5-3 所示:
图 5-3。
玩家在矩形区域内的位置
从图中我们可以清楚地看到,玩家在矩形内。我们如何让计算机检查玩家是否在矩形内,并做出相应的响应?这是在 2D 空间——二维空间;玩家位置的水平和垂直分量,即他们的 x 和 y 坐标。最简单的方法是把它分成两个独立的 1D 检查,然后把两个检查的结果结合起来。在英语中:
如果玩家的 x 坐标介于 0 和 100 之间,y 坐标介于 25 和 250 之间,则他们在该区域内。
在代码中,这看起来像
x = 50
y = 50
if x >= 0 and x <= 100 and y >= 25 and y <= 250:
print("Player is inside the area. Sound the alarm!")
else:
print("Player is outside the area. Do nothing")
使用布尔逻辑
正如我们在前一章中看到的,计算机使用布尔逻辑:任何问题,只要它能得出正确或错误的答案。下列布尔关键字可用于使 If 条件更复杂:
-
和
-
或者
-
不
和
只有当两个条件都为真时,if 语句中的 And 才等于 true:
isRaining = True
isSunny = True
if isRaining and isSunny:
print("Sun showers")
在游戏的上下文中,你可能有一个条件来测试玩家是否有一把钥匙,他或她撞上了一扇门,然后打开了门:
if playerHasKey and playerHitDoor:
OpenTheDoor()
RemoveKeyFromInventory()
OpenTheDoor()和 RemoveKeyFromInventory()这两个方法是程序员做的;它们不是 Python 的一部分。我们将在后面的章节中学习如何创建用户自定义函数。
在布尔逻辑中,真值表用于显示运算的结果(“与”、“或”、“非”)。通常,这显示了称为“A”和“B”的两个输入的值和一个结果。
表 5-2 中所示的‘和’的真值表如下。
表 5-2。
和“真值表”
|A
|
B
|
结果
| | --- | --- | --- | | 假 | 错误的 | 错误的 | | 假 | 真实的 | 错误的 | | 真 | 错误的 | 错误的 | | 真 | 真实的 | 真实的 |
这说明对于' and ',只有当' A '和' B '都为真时,' A '和' B '的组合结果才能为真。
或者
或者在“if”语句中,如果两个条件中的一个为真,则“if”将等于“true ”:
isRaining = True
isSunny = False
if isRaining or isSunny:
print("Some kind of weather out there")
else:
print("No weather! How unusual for this time of year")
“或”的真值表如表 5-3 所示:
表 5-3。
或“真值表”
|A
|
B
|
结果
| | --- | --- | --- | | 假 | 错误的 | 错误的 | | 假 | 真实的 | 真实的 | | 真 | 错误的 | 真实的 | | 真 | 真实的 | 真实的 |
这说明只有当' A '和' B '都为假时' or '才为假。
不
Not 用来否定一个条件:把它从真变为假,反之亦然。这是一元运算符,仅在一种情况下有效:
isRaining = True
isSunny = False
if isRaining and not isSunny:
print("It's raining and not sunny")
else:
print("Sun showers")
“not”的真值表(表 5-4 )的不同之处在于,它只有一个输入,因为它是一元运算符。因此,真值表只有“A”输入。
表 5-4。
“非”真值表
|A
|
结果
| | --- | --- | | 假 | 真实的 | | 真 | 错误的 |
您可以看到,无论输入是什么,not 关键字都会将其否定。
嵌套 if
当我们需要根据大量事实做出复杂的决定时,我们可以做所谓的“嵌套”这意味着将一个“if”代码块放在另一个“if”代码块中,例如:
isRaining = True
isCloudy = True
if isRaining:
print("I will take my umbrella to work today")
elif isCloudy:
print("It looks like it will rain. I'll take my umbrella")
else:
print("It is sunny. I'll not bother with the brolly")
表 5-5 中显示了这方面的真值表,以使前面的示例更加清晰。
表 5-5。
“if”块真值表
|下雨了
|
多云
|
输出
| | --- | --- | --- | | 真 | 真实的 | 我今天要带伞去上班 | | 真 | 错误的 | 我今天要带伞去上班 | | 假 | 真实的 | 看起来要下雨了,我要带着雨伞以防万一 | | 假 | 错误的 | 天气晴朗。我不会为这个麻烦的 |
因此,IF 语句的格式是
if condition:
Action(s)
[else:
Action(s)]
[elif condition:
Action(s)]
关于开关的一个注记
对于其他语言的用户,你应该注意到 Python 中没有“switch”语句。它是为语言而提出的,但最终被否决。在像 Python 这样的 OO(面向对象)语言中,“switch”可以用多态来代替(我们后面会讲到!)来电。Stack Overflow(一个很棒的网站,也是您应该收藏的网站)有一篇关于如何避开“切换”的文章
详见 http://stackoverflow.com/questions/126409/ways-to-eliminate-switch-in-code 。switch 关键字可以很容易地使用 ifs 实现,如下所示:
character = input("Enter command (help, list): ")
if character == "help":
print("The help screen goes here")
elif character == "list":
print("List the items here")
else:
print("Invalid command!")
结论
计算机非常擅长快速做出简单的决定。使用比较和范围运算符,可以确定两个值是否相等,或者它们是否在一个范围内(例如,在 1 和 10 之间)。
可以使用布尔逻辑操作符(如 And、Or、Not 和 If 关键字)来组合这些决策,以生成分支代码;如果为真,运行一些代码,如果为假,运行一些其他代码。我们将在后面的章节中看到这些小积木如何构建复杂的系统。
六、让树莓派重复
电子游戏重复这个动作,直到所有玩家的生命都消失了,或者游戏结束了。到目前为止,我们只编写了运行一系列命令然后终止的程序。通过使用某些 Python 关键字,我们可以让计算机在需要时重复一段代码,或者使用条件,或者重复设定的次数。
for 循环
Python 中的“for 循环”接受一个列表,并对列表中的每一项执行一系列操作。这些操作包含在“:”字符后面的代码块中,并向右移动一个制表符。图 6-1 中的流程图显示了“for”循环内部发生的情况。
图 6-1。
显示 for 循环的流程图
例如,下面的程序将打印数字 1 到 5。我们稍后将讨论 range()函数的一些奇怪之处。
不要忘了脚本顶部的 hash-bang!请记住,您需要使用 hash-bang 来从命令提示符运行脚本文件。您还需要更改文件模式(chmod)并添加可执行文件标志。如果你不太记得怎么做,请参见第四章(“从解释器中挣脱”)。
for i in range(1, 6):
print(i)
这里的“I”变量有特殊的含义。它充当回路的控制。事实上,我们给任何控制流量的变量命名为控制变量。同样,这只是我给变量的一个名字。我可以叫 n 或者 j 或者 fred。控制变量往往有简短的名字。我选择这个是因为我们要遍历整数或整数,而‘I’似乎适合这个任务。
“for”循环的格式为
for condition:
Action(s)
其中“条件”是生成列表的任何语句。
range()函数
range()函数由 Python 提供,因此被称为内部函数。它生成一个从起始值到 1-n 的数字列表,其中 n 是范围内的最后一个值。以下示例摘自 Python 解释器中输入的语句:
>>> range(1,6)
[1, 2, 3, 4, 5]
>>> range(2,4)
[2, 3]
您还可以指定第三个参数。此参数指示在“for”循环的每次迭代后添加到每个数字的计数。默认值为 1(一),这就是为什么您不需要提供它:
>>> range(10, 255, 10)
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250]
>>> range (10, 0, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
没错,你甚至可以用负值从一个较大的数迭代到一个较小的数。
我们将在下一章讨论列表和字典,但是我们已经知道‘for’循环遍历列表。所以,如果我们没有数字呢?如果我们有电视上角色的名字会怎么样:
names = ['John', 'Anne', 'Fred', 'Beth']
for name in names:
print(name)
“names”变量被赋予一个人名列表的值。“for”循环遍历每个名字,并将它们打印在屏幕上。本例中的控制变量是“名称”在循环的每次迭代中,列表中的下一个名字将被取出并处理。
While 循环
For 循环非常适合遍历一个固定的列表,但是如果我们不知道我们有多少项呢?例如,读取文件内容或从网站获取数据。这就是“while”关键字出现的地方。
尽管无论使用哪种循环,while 循环都具有相同的格式,但是 while 循环有三种类型:
-
计算
-
哨兵
-
有条件的
计算
计数 while 循环基本上只是“for”关键字的替代品。当然,你可以用它来代替' for '关键字,但是它看起来不那么优雅。例如:
#!/usr/bin/python
i = 1
while i < 6:
print(i)
i = i + 1
在这个例子中,我保留了 hash-bang。
在“for”循环中,控制变量包含在“for”语句中,而在“while”循环中,控制变量是在循环外定义的。程序员还必须每次手动更新所需步骤的控制变量。
不要忘记更新控制变量!如果你不这样做,你将会陷入一个无限循环,你将不得不使用 Ctrl + C 退出你的程序!
请注意,“while”语句的格式是
while condition:
Action(s)
“where 条件”是一个等同于“真”或“假”的语句:一个布尔值。这类似于“if”关键字,因为它也采用布尔条件作为其参数。该“while”循环的流程图如图 6-2 所示。
图 6-2。
示例“while”循环的流程图
从流程图中我们可以看到,只有当布尔条件为“真”时,才会执行“while”块中的语句
这意味着“while”循环的条件充当了块内各行的看门人。如果条件不成立,就不要执行里面的行。将“I”的初始化更改为 6:
#!/usr/bin/python
i = 6
while i < 6:
print(i)
i = i + 1
运行脚本。会发生什么?没什么?完全没有输出。这是因为 i< 6,当 i = 6 时返回‘False’。
哨兵
sentinel while 循环是一种不断循环直到达到某个值的循环。
让我们回到上一章的菜单例子。我们有三个命令:列表、帮助和退出。当用户选择退出时,程序结束。
我们不知道用户在整个程序会话中会使用多少个命令,也不知道他们会使用多少次相同的命令。这是“while”循环的理想用例,因为它可用于在条件未满足时保持程序运行:
cmd = input("Command: ")
while cmd != 'quit':
if cmd == 'help':
print("Put help here")
elif cmd == 'list':
print("Put list here")
else:
print("Invalid command!")
cmd = input("Command: ")
当我们开始进入多个标签时,你必须保持正确的间距。在您的编辑器中,您应该会看到如图 6-3 所示的程序。
图 6-3。
显示缩进代码行的菜单程序
如果 input()函数对您不起作用,请尝试 raw_input(),因为您可能正在运行 Python 2.7
以下是运行该程序的典型输出:
Command: help
Put help here
Command: list
Put list here
Command: badcommand
Invalid command!
Command: quit
有条件的
这些是前两者的结合:计数和哨兵。这是当你想计数一个序列,但你不知道你是什么序列计数。假设你想写一个程序把所有的数字加起来达到某个值。您可能会这样写:
#!/usr/bin/python
topNum = int(input("Sum of numbers to? "))
count = 0
while topNum > 0:
count += topNum
topNum = topNum - 1
print("Sum of all numbers is %d" % count)
要获得数字形式的输入,我们必须使用 int()函数将其转换为整数。
input()函数总是返回一个字符串!
结论
计算机程序中经常使用循环。根据具体情况,您必须选择使用哪个循环:for 循环还是 while 循环。
如果范围是已知的,或者您想要循环遍历一个值列表(就像本章中的名称示例),那么 for 循环非常适合您。
while 循环有三种类型:计数循环、标记循环和条件循环。计数版本很少使用,大多数人更喜欢“for”循环。然而,sentinel 和 conditional 被广泛用于保持循环,直到满足某个未知条件(通常在编写时)。
七、容器
到目前为止,我们主要是在一个变量中存储一个值,如下所示:
playerName = 'Sloan'
Python 允许在同一个变量中存储多个值。在这种情况下,您将为容器对象指定一个名称。有三种不同类型的容器:
-
元组
-
目录
-
词典
在有些情况下,您会使用其中一种而不是另一种,我们将讨论每种用法的利弊。
容器术语
容器子部分称为元素。每个元素都可以使用“[”和“]”字符进行索引,并指定一个介于 0 和 n-1 之间的数字,其中“n”是它们之间的容器中的项目数。我们将在元组部分看到这是如何工作的。
元组
元组是不可变的对象集合。集合中的元素和容器本身都不能修改。这意味着不能在元组中添加和删除元素。
对于视频游戏,你可能想把玩家的位置——他们的 x 和 y 坐标——存储在一个元组中。
元组是对象的列表,可以是文字或变量名,用逗号分隔,并用括号字符“(”和“)”括起来。例如:
('sloan', 'robert')
若要访问元组中的元素,请使用“[”和“]”字符,并将索引值放在它们之间。假设您需要数组中的第一个元素,那么您应该像这样指定“0”:
('sloan', 'robert')[0]
这将显示
'sloan'
从元组中移除元素
如果你想从一个元组中删除项目(你不能),但有一个办法。创建新的元组!假设您有一个包含五个元素的元组,但是您不想要第三个元素:
numbers = (1, 2, 3, 4, 5)
tuple(x for x in numbers if x != 3)
哇哦!这看起来不必要的复杂!这是因为元组是不可变的,这意味着它们不能改变。让我们稍微分解一下复杂性。tuple()函数从给定的序列中返回一个元组。例如:
>>> tuple('abcdef')
('a', 'b', 'c', 'd', 'e', 'f')
>>> tuple(['sloan', 'robert'])
('sloan', 'robert')
在前一个例子中,字符串被分割成单独的字符。后者包含一个名称列表,并根据该列表创建一个元组。
完成所有魔法的部分叫做列表理解。它用于基于现有列表创建列表。
x for x in range(0, 5) if x != 3
列表理解接受一个列表,处理列表中的每个元素,并生成另一个列表。正如我们已经看到的,tuple()关键字从任何序列中生成一个元组。字符串是字符序列,元组是(不可变的)对象序列,列表也是对象序列。
不要太拘泥于那种陈述的格式;这仅仅是如何从元组中移除项目的一个例子。
更改元素值
元组的另一个‘不能做’。但是,也有一种方法可以解决这个问题。元组是不可变的,这意味着它们不能被改变,它们的元素也是如此。唯一的选择是创建另一个元组。
在这个例子中,我们有一个表示玩家的 x 和 y 坐标的元组(“playPos”)和另一个表示玩家的速度(“speed”)的元组。为了得到玩家的下一个位置,我们把速度加到当前位置。记住,我们不能改变元组或它的元素。我们必须创建一个新元组,并将该值赋给“playPos”:
playPos = (5, 4)
print("playPos = %d, %d" % playPos)
speed = (2, 1)
playPos = (playPos[0] + speed[0], playPos[1] + speed[1])
print("playPos = %d, %d" % playPos)
该行:
playPos = (playPos[0] + speed[0], playPos[1] + speed[1])
在等号的右边,创建了新的元组。这就被命名为“playPos”分配给“playPos”的元组被这个新值覆盖。这相当于以下简单的赋值:
>>> num = 5
>>> print(num)
5
>>> num = 10
>>> print(num)
10
在本例中,值“num”最初被赋值为 5。然后给它赋值 10。这将覆盖最初存储在“num”中的值
印刷中的元组
我们以前在显示格式化字符串时使用过元组。例如:
>>> numbers = (1, 2, 3, 4, 5)
>>> print("%d %d %d %d %d" % numbers)
1 2 3 4 5
解构元组
另一个常见的动作是将元组解构为其组成部分,并将它们分配给单独的变量。这是通过把要赋值的变量放在等号的左边,把元组放在另一边来实现的。在下面的例子中,我们有一个包含两个元素的向量“vec ”:一个用于 x 坐标,另一个用于 y 坐标:
>>> vec = (2, 3)
>>> x, y = vec
>>> x
2
>>> y
3
>>>
类似地,也可以通过指定逗号分隔的值来构造元组。这个我不推荐;我更喜欢使用带括号的显式语法,但这也同样有效:
>>> vec2 = x, y
>>> vec2
(2, 3)
>>>
列表
列表是可变的容器。这意味着元素和列表本身都可以改变。对于列表来说,这意味着我们可以在创建列表后添加和删除元素。使用 append()方法将项目添加到列表中,通过 remove()方法移除项目。方法是对象可以执行的操作。我们将在本文的面向对象部分看到更多的方法。
列表在电子游戏中被大量使用。你的物品清单是一个物品列表,屏幕上的精灵(图像)存储在一个列表中,组成游戏的关卡集合也可以存储在一个列表中。
列表创建
您可以创建一个空白列表,也可以创建一个最初填充了值的列表:
blankList = []
populatedList = [1, 2, 3, 4, 5]
如果我们在 Python 解释器中运行这些命令,其输出将是
>>> blankList = []
>>> populatedList = [1, 2, 3, 4, 5]
>>> blankList
[]
>>> populatedList
[1, 2, 3, 4, 5]
>>>
向列表中添加值
如果我们想向“空白列表”添加值,我们只需使用 append()方法,并将我们想要添加的内容放在括号内:
>>> blankList.append("Python")
>>> blankList
['Python']
>>>
添加另一个计算机语言名称(这次是 Lua)将意味着我们的空白列表将包含
>>> blankList.append("Lua")
>>> blankList
['Python', 'Lua']
>>>
从列表中删除值
要从列表中删除一个项目,remove()方法的用法如下:
>>> populatedList = [1, 2, 3, 4, 5]
>>> populatedList.remove(3)
>>> populatedList
[1, 2, 4, 5]
>>>
您还可以通过索引值从列表中移除项目。在列表中没有内置的方法来做到这一点;相反,我们使用“del”关键字。例如,要删除第一个元素,即索引 0(零),我们可以使用
>>> populatedList = [1, 2, 4, 5]
>>> del populatedList[0]
>>> populatedList
[2, 4, 5]
>>>
这意味着我们也可以删除多个项目;假设我们想从列表中删除所有项目。我们会这样做:
>>> populatedList = [2, 4, 5]
>>> del populatedList[:]
>>> populatedList
[]
>>>
并再次填充列表:
populatedList = [1, 2, 3, 4, 5]
假设我们想从列表中删除 2 和 3。我们可以发出这一行两次:
del populatedList[1]
为什么两次?列表的索引 1 是“2”元素。当我们删除列表中的某个内容时,之后的所有内容都会上移一个位置。因此,该数组现在包含
[1, 3, 4, 5]
这意味着索引 1 现在包含“3”
当我们可以一次完成所有任务时,两次键入相同的命令有点浪费。我们可以使用冒号(':')来指定要删除的值的范围。现在,要同时删除 2 和 3,我们可以使用
del populatedList[1:3]
冒号前的数字是删除的起始索引。列后的数字是 1 加上要删除的元素数。如果您想删除从第一个元素开始的所有内容,您可以使用
del populatedList[1:]
医生候诊室计划
我创建了一个简单的程序,以医生候诊室为例演示列表。用户可以添加患者,在呼叫时将他们从列表中删除,以及退出程序。所有的动作都是通过一个菜单完成的。
#!/usr/bin/python3
names = [] # an empty list of names
我们每天早上从一张空白清单开始。
cmd = ""
while cmd != '4':
有四个命令:1–列出姓名,2–添加姓名,3–呼叫下一位患者,4–退出。用户的命令将存储在“cmd”变量中。请注意,我们有一个“while”循环来保持用户在程序中,直到他们选择退出。
print("1\. List names")
print("2\. Add name")
print("3\. Call next patient")
print("\n4\. Quit")
显示菜单是为了让用户知道他们可以选择的选项。
cmd = input("\rCommand : ")
现在会提示用户输入命令。我们现在将使用一系列嵌套的 if 来执行用户选择的命令。
if cmd == '1':
for name in names:
print (name)
print ("\n")
如果用户输入‘1’,那么我们使用‘for’循环遍历‘names’列表中的所有名字。在每次迭代中,我们打印病人的名字。最后,我们用一个换行符(' \n ')结束它,在屏幕上给我们一些空白。
elif cmd == '2':
newName = input("Name : ")
names.append(newName)
如果用户输入“2 ”,我们会提示他们输入新到达的患者的姓名。然后,我们使用 append()方法将新名称添加到名称列表中。
elif cmd == '3':
if len(names) == 0:
print ("There are no more patients!")
else:
nextPatient = names[0]
names.remove(nextPatient)
print ("Calling %s" % nextPatient)
对于第三个也是最后一个命令,但不是我们程序的结尾,用户选择呼叫下一个要看的病人。这种做法提供了严格的先到先得的政策。这意味着列表中的第一项被删除。但是,如果列表中没有项目,则会显示一条警告消息。您可以使用“len”关键字来确定项目列表的长度。
elif cmd != '4':
print ("Invalid command!")
程序的最后几行用来让用户知道他们输入了无效的命令:不是 1、2、3 或 4。
将程序保存为“patients.py”(不带引号),并且不要忘记更改程序的属性以允许它被执行。记住!您只需更改一次:
$ chmod +x patients.py
要运行该程序:
$ ./patients.py
当你和程序在同一个目录的时候。
字典
字典是一组键/值对。这意味着您可以使用用户定义的密钥来访问信息,而不是索引号。
电子游戏中可以使用字典来查找相关数据。例如,如果你想查看一把特定的剑造成的伤害,你可以使用字典来存储游戏中每种武器的数据。您可以对列表做同样的事情,但是遍历列表需要时间,一次一个元素来查找数据。当你想快速找到某样东西时,使用字典。
例如,我们将定义一个包含不同人的电话号码的字典。一个人的电话号码可以通过姓名获得:
>>> numbers = {'Sloan':'416-555-1234', 'Kevin':'212-555-4321'}
>>> numbers['Sloan']
'416-555-1234'
>>>
第一行定义了包含两个条目的字典“numbers”。每个条目都是一个单独的键/值对。每个键/值用冒号“:”分隔,每对用逗号“,”分隔。
遍历字典
我们可以使用字典的 iteritems()方法遍历每个条目:
>>> for k,v in numbers.iteritems():
... print ("%s = %s" % (k ,v ))
...
Sloan = 416-555-1234
Kevin = 212-555-4321
>>>
向词典中添加新项目
字典有一个更简单的添加新条目的方法:如果一个键不存在,该值被添加到字典中。如果一个键已经存在,那么新值被分配给该键。
>>> numbers['Frank'] = '216-555-1234'
>>> numbers
{'Sloan': '416-555-1234', 'Frank': '216-555-1234', 'Kevin': '2
>>>
从字典中删除条目
为了从字典中删除一个词条,我们使用我们的老朋友“del”从“数字”字典中去掉“斯隆”
>>> del numbers['Sloan']
>>> numbers
{'Frank': '216-555-1234', 'Kevin': '212-555-4321'}
>>>
结论
我们已经看到 Python 为我们提供了三种不同类型的容器,为我们的程序提供了选项。元组可以用来像不可变(不能被改变)的项目一样分组在一起。用一个元组定义一个结构线空间中的一个点。空间中一个点的属性是它的 x 和 y 坐标。这两个元素不会改变,你很少迭代(循环)它们。列表容器可用于存储可添加和移除的项目集合。最后,字典允许添加、删除和修改条目。
我们现在要从 Python 语言中休息一下,看看如何着手设计一个游戏,并跳跃到 Raspberry Pi 使用的名为 LXDE 的窗口系统。这是因为我们将在接下来的几章中开始研究 PyGame。