第 2 章 记住内存和变量

第 2 章 记住内存和变量

什么是程序?嘿,等等,我想我们在第 1 章已经回答过这个问题!我们说过,程序就是下达给计算机的一系列指令。

对,确实是这样。不过,几乎所有真正有用或者有意思的程序都还有一些别的特征:

  • 都有输入(input);

  • 都会处理(process)输入;

  • 都会产生输出(output)。

2.1 输入、处理和输出

你的第一个程序(代码清单 1-1)并没有任何输入或处理。也正是因为这个原因,那个程序没有太大意思。它的输出就是程序在屏幕上打印的消息。

你的第二个程序猜数游戏(代码清单 1-2)就具备以下这三个基本要素。

  • 输入:玩家键入的数,也就是他猜的数。

  • 处理:程序检查玩家猜的数,并统计已经猜过几次。

  • 输出:程序最后打印的消息。

下面再看一个例子,这个程序也具备所有这三个基本要素:在一个视频游戏中,输入是来自操纵杆或游戏控制器的信号,处理是程序确定你是否击中外星人、避开火球、顺利过关或者做其他活动,输出是屏幕上显示的图形和扬声器或耳机传出的声音。

{%}

输入、处理和输出。一定要把这些记住。

那好,这么说计算机需要输入。不过它会怎么处理这些输入呢?为了处理输入,计算机必须记住它们,或者把它们保存在某个地方。计算机会把这些内容(包括输入以及程序本身)保存在它的内存中。

到底怎么回事?

你可能听说过计算机内存,不过这到底是什么意思呢?

我们说过,计算机只是一大堆开关。不错,内存就像是放在同一个位置上的一组开关。一旦以某种方式设置了这些开关,它们就会一直保持那种状态,直到你做出改变。也就是说,它们会记住你原先的设置……

哇,内存!

你可以写内存(设置开关),或者读内存(查看开关如何设置,不过不做任何改变)。

但是我们怎么告诉 Python 要把一个东西放在内存中的某个位置呢?另外,放在那里之后,又怎么再把它找回来呢?

在 Python 中,如果希望程序记住某个东西,以便你以后使用,所要做的就是给这个“东西”起一个名字。Python 会在计算机的内存中为这个“东西”留出位置,可能是数字、文本、图片或者音乐。下次想要引用这个东西时,只需要使用同一个名字。

下面还是在交互模式中使用 Python,对名字多做一些研究吧。

2.2 名字

再回到 Python Shell 窗口。(如果完成第 1 章中的例子后关闭了 IDLE,现在要再打开它。)在提示符后面键入:

>>> Teacher = "Mr. Morton"
>>> print Teacher

(记住,>>> 是 Python 显示的提示符。你只需要键入它后面的内容,然后按回车。)你会看到下面的结果:

Mr. Morton
>>>

你刚才创建了一个由字母 "Mr. Morton" 组成的东西,并且给它起了一个名字 Teacher

这里的等号(=)告诉 Python 要赋值(assign)或者“让……等于……”。这里把字母序列 "Mr.Morton" 赋值给名字 Teacher

{%}

在计算机内存中的某个位置,字母序列 "Mr.Morton" 已经存在。你不需要准确地知道它们到底在哪里。只需要告诉 Python 这个字母序列的名字是 Teacher,从现在开始就要通过这个名字来引用这个字母序列。名字就像标签或者不干胶便条,你可以用它来标识一些东西。

在一个东西两边加上引号时,Python 会按字面来处理它。它会把引号里的内容原样打印出来。如果没有加引号,Python 就必须明确这个东西到底是什么。这可能是数字(如 5)、表达式(比如 5 + 3)或者名字(如 Teacher)。由于我们创建了名字 Teacher,所以 Python 会打印这个名字里的内容,这正是字母序列 "Mr. Morton"

这就像有人在说,“请写下你的地址”,你肯定不会这样写(如下图):

(不过,也许卡特会这么干,因为他总是喜欢调皮捣蛋……)

你可能会这样写:

如果写成“你的地址”,就是在按字面看这句话。除非加上引号,否则 Python 不会按字面来处理。下面来看另一个例子:

>>> print "53 + 28"
53 + 28
>>> print 53 + 28
81

有引号时,Python 会直接照你所说显示输出:53 + 28。

没有引号时,Python 把 53 + 28 处理为一个算术表达式,它会计算这个表达式。在这里,这是一个两数相加的表达式,所以 Python 会给出它们的和。

术语箱

算术表达式(arithmetic expression)是数字和符号的一个组合,Python 可以算出它的值。

计算(evaluate)就表示“算出……的值”。

Python 要确定需要多少内存来存储这些字母,以及要使用哪一部分内存。要获取信息(取回信息),只需要再使用同样的名字。我们使用 print 关键字并提供名字,这会在屏幕上显示具体的内容(如数字或文本)。

像程序员一样思考

把一个值赋给一个名字时(如把值“Mr. Morton”赋给 Teacher),它会存储在内存中,称为变量(variable)。在大多数编程语言中,都把这称为“把值存储(store)在变量中”。

不过 Python 与大多数其他计算机语言的做法稍有不同。它并不是把值存储在变量中,而更像是把名字放在值上。

有些 Python 程序员说,Python 没有“变量”,而是只有“名字”。不过其实它们的行为基本上是一样的。这是一本关于编程的书(只不过刚好使用了 Python),而不是专门讨论 Python 的。所以谈到 Python 名时,我们可能会交替使用变量(variable)、名字(name)或变量名(variable name)等不同的术语。实际上,只要你理解变量有什么表现以及在程序中如何使用变量,怎么称呼并不重要。

顺便说一句,Guido van Rossum(也就是创建 Python 的那个人)在他的 Python 教程中曾经这样讲:“‘=’符号用来将一个值赋给一个变量。”所以我猜他认为 Python 是有变量的!

 

一种简洁的存储方法

在 Python 中使用名字就像是干洗店给衣服加标签。你的衣服挂在晾衣架上,上面附着写有你的名字的标签,这些衣服都挂在一个巨大的旋转吊架上。你回来取衣服时,并不需要知道它们存放在这个大型吊架的具体哪个位置。只需要提供你的名字,干洗店的人就会把衣服交还给你。实际上,你的衣服可能并不在原先所放的位置。不过干洗店的人会为你记录衣服的位置。要取回你的衣服,只需要提供你的名字。

变量也一样。你不需要准确地知道信息存储在内存中的哪个位置。只需要记住存储变量时所用的名字,再使用这个名字就可以了。

除了字母,还可以为其他内容创建变量。可以给数值指定名字。你应该还记得前面的例子:

>>> 5 + 3
8

下面用变量来完成这个例子:

>>> First = 5
>>> Second = 3
>>> print First + Second
8

在这里,我们创建了两个名字 FirstSecond。数字 5 赋给 First,数字 3 赋给 Second。然后用 print 把这两个数的和打印出来。下面是完成这个例子的另一种做法。你可以试试看:

>>> Third = First + Second
>>> Third
8

注意这里的做法。在交互模式中,只需键入变量名就可以显示这个变量的值,而不必使用 print。(不过程序中可不行。)

在这个例子中,并没有在 print 指令中求和,而是先取 First 的值和 Second 的值,将二者相加,创建一个新的值,名为 ThirdThirdFirstSecond 的和。

{%}

同一个东西可以有多个名字,可以在交互模式中试试这个指令:

>>> MyTeacher = "Mrs. Goodyear"
>>> YourTeacher = MyTeacher
>>> MyTeacher
"Mrs. Goodyear"
>>> YourTeacher
"Mrs. Goodyear"

{%}

这就像在同一个东西上贴两个标签。一个标签写着 YourTeacher,另一个标签写着 MyTeacher,不过它们都贴在 "Mrs. Goodyear" 上。

卡特,这个问题问得好。答案是:不会。实际上,修改这个名字会创建一个新的值 "Mrs.Tysick"。标签 MyTeacher 会从 "Mrs.Goodyear" 上撕掉,贴到 "Mrs. Tysick" 上。你仍然有两个不同的名字(两个标签),不过,现在它们分别贴在两个不同的东西上,而不再贴在同一个东西上了。

{%}

2.3 名字里是什么

可以给变量取你喜欢的任何名字(严格地说,应该是几乎任何名字)。名字长短由你来定,里面可以有字母和数字,还可以有下划线(_)。

不过对于变量名还有几条规则。最重要的一点是名字是区分大小写的,即大写和小写是不同的。所以 teacherTEACHER 是两个完全不同的名字。同样,firstFirst 也不相同。

另一条规则是变量名必须以字母或下划线字符开头。不能以数字开头,所以 4fun 不能作为变量名。

还有一条规则,变量名中不能包含空格。

如果你想知道 Python 中有关变量名的所有规则,可以查看本书后面的附录 A。

从前的美好时光

在一些较早的编程语言中,变量名的长度只能是一个字,而且有些计算机只有大写字母,这说明变量名只有 26 种选:A ~ Z !如果程序中需要的变量超过 26 个,那就难办了!

2.4 数字和字符串

目前为止,我们已经为字母(文本)和数字创建了变量。不过,在前面的加法例子中,Python 怎么知道我们指的是数字 5 和 3,而不是字符“5”和“3”呢?就像前面这句话一样,正是引号带来了差别。

字符或字符序列(字母、数字或标点符号)称为一个字符串(string)。要告诉 Python 你在创建一个字符串,就要在字符两边加上引号。至于使用单引号还是双引号,Python 并不太挑剔。单引号和双引号都是可以的:

{%}

不过,字符串的开头和结尾必须使用同种类型的引号(要么都是双引号,要么都是单引号)。

如果键入一个数字而没有加引号,Python 就会知道这表示数值,而不是字符。可以试试看二者的区别:

>>> first = 5
>>> second = 3
>>> first + second
8 
>>> first =    '5'
>>> second = '3'
>>> first + second
'53'

没有引号时,5 和 3 都处理为数字,所以我们会得到二者的和。有引号时,'5''3' 处理为字符串,所以会得到两个字符“相加”的结果,也就是 '53'。还可以把由字母构成的字符串“加”在一起,第 1 章中已经见过这样的例子:

>>> print "cat" + "dog"
catdog

要注意,像这样将两个字符串相加时,它们之间没有空格。两个字符串会紧紧地拼接在一起。

注意!这个词有意思!

拼接

谈到字符串时我们说把它们“相加”(刚才就这么说过),不过这并不完全正确。把字符或字符串放在一起构成更长的字符串时,有一个特殊的称呼。并不是“相加”(相加只适用于数字),而是称为拼接(concatenation)。

我们会说拼接两个字符串。

长字符串

如果希望得到一个跨多行的字符串,必须使用一种特殊的字符串,称为三重引号字符串(triple-quoted string),就像下面这样:

long_string = """Sing a song of sixpence, a pocket full of rye,
Four and twenty blackbirds baked in a pie.
When the pie was opened the birds began to sing.
Wasn't that a dainty dish to set before the king?"""

这种字符串以 3 个引号开头和结尾。所用的引号可以是双引号也可以是单引号,所以也可以写成下面的形式:

long_string = '''Sing a song of sixpence, a pocket full of rye,
Four and twenty blackbirds baked in a pie.
When the pie was opened the birds began to sing.
Wasn't that a dainty dish to set before the king?'''

如果希望多行文本显示在一起,而且你不希望每一行都使用一个单独的字符串, 在这种情况下,三重引号字符串就非常有用。

2.5 它们有多“可变”

变量之所以叫做“变量”是有原因的,就是因为它们是……怎么说呢……是可变的!这是指你可以改变赋给它们的值。在 Python 中,这就要创建一个与原先不同的新东西,并把旧标签(名字)贴到这个新东西上。上一节中我们就采用这种方式改变了 MyTeacher。我们将标签 MyTeacher"Mrs. Goodyear" 上取下来,把它贴到一个新东西 "Mrs. Tysick" 上。这样就为 MyTeacher 赋了一个新值。

{%}

下面再来试一个例子。还记得之前创建的变量 Teacher 吗?嗯,如果你还没有关闭 IDLE,这个变量就还在。可以检查看看:

>>> Teacher
'Mr. Morton'

没错,确实还在。不过现在可以把它改成其他内容:

>>> Teacher = 'Mr. Smith'
>>> Teacher
'Mr. Smith'

我们创建了一个新东西 "Mr. Smith",并把它命名为 Teacher。我们的标签从原来的值上取下来,贴到了这个新东西上。不过原来的 "Mr. Morton" 怎么样了呢?

应该记得,一个东西可以有多个名字(上面可以贴多个标签)。如果 "Mr. Morton" 上还有另一个标签,那么它还在计算机的内存里。不过,如果它上面再没有任何标签了,标签被移走 Python 就会发现再没有人需要它了,所以会把它从内存中删除。

这样一来,内存中就不会塞满那些没人用的东西。Python 会自动完成所有这些清理工作,根本不用你操心。

还有一点很重要,这里并没有真的把 "Mr. Morton" 改成 "Mr. Smith"。我们只是把标签从一个东西移到另一个东西上(重新指派名字)。Python 中有些东西(如数字和字符串)是不能改变的。你可以把它们的名字重新指派到其他东西上(就像我们刚才所做的一样),但是并不能对原先的东西做任何改变。

Python 中还有一些东西是可以改变的。第 12 章介绍列表(list)时我们会更多地讨论这方面的内容。

2.6 全新的我

还可以创建一个等于自己的变量:

>>> Score = 7
>>> Score = Score

我敢打赌,你肯定在想:“什么嘛,这一点儿用都没有!”你的想法没错。这实际上就是在说“我是我”。不过,稍稍做点改变,你就能成为一个全新的你!试试看:

{%}

这里发生了什么?在第一行中,Score 标签本来贴在值 7 上。我们创建了一个新东西:Score + 1,也就是 7 + 1。这个新东西是 8。然后把 Score 标签从原来的东西(7)上取下来,贴到这个新东西(8)上。所以 Score7 重新指派到 8

要让变量等于某个东西,这个变量总会出现在等号(=)左边。巧妙的是,变量也可以出现在等号右边。这很有用,在很多程序中都会看到。最常见的用法是让变量自增(increment),也就是让它增加某个量(就像前面所做的),或者与之相反,也可以让变量自减(decrement),让它减少某个量。

  • 开始时 Score = 7。

  • 让它增加 1(得到 8),创建一个新东西。

  • 把名字 Score 赋给这个新东西。

这样一来,Score 就从 7 变成了 8。

关于变量,有几个重要的问题必须记住。

  • 程序可以在任何时间对变量重新赋值(把标签贴在新东西上)。这一点很重要,必须记住,因为编程中最常见的 bug 就是改变了不该改变的变量,或者尽管改变的变量无误,但是时机不合适。

    要避免这种情况,有效的方法是使用容易记的变量名。我们可能用过下面这 两个变量名:

    t = 'Mr. Morton'
    
    

    x1796vc47blahblah = 'Mr. Morton'
    
    

    不过这样在程序中会很难记住。如果使用这些变量名,出错的可能性会更大。应该尽量使用能够说明用途的名字,可以告诉你变量要用来做什么。

  • 变量名区分大小写。这说明大写和小写是不同的。所以 teacherTeacher 是两个完全不同的名字。

记住,如果想了解 Python 的所有变量命名规则,可以查看附录 A。

像程序员一样思考

我们曾经说过,你可以为变量取任何名字(不过前提是要满足命名规则),这一点不假。你可以把变量叫做 teacher 或者 Teacher,这两个名字都是可以的。

专业的 Python 程序员给变量命名时几乎总是以小写字母开头,其他计算机语言可能会采用不同风格。是否遵循 Python 风格由你来决定。因为我们使用的是 Python,所以这本书后面都会遵循这种风格。

你学到了什么

这一章中,你学到了以下内容。

  • 如何使用变量在计算机内存中“记住”或保存信息。

  • 变量也叫做“名字”或“变量名”。

  • 变量可以是不同类型的东西,如数字和字符串。

测试题

1. 如何告诉 Python 变量是字符串(字符)而不是数字?

2. 一旦创建一个变量,能不能改变赋给这个变量的值?

3. 变量名 TEACHERTEACHEr 相同吗?

4. 对 Python 来说,'Blah'"Blah" 一样吗?

5. 对 Python 来说,'4' 是不是等同于 4 ?

6. 下面哪个变量名不正确?为什么?

 (a) Teacher2

 (b) 2Teacher

 (c) teacher_25

 (d) TeaCher

7. "10" 是数字还是字符串?

动手试一试

1. 创建一个变量,并给它赋一个数值(任何数值都行)。然后使用 print 显示这个变量。

2. 改变这个变量,可以用一个新值替换原来的值,或者将原来的值增加某个量。使用 print 显示这个新值。

3. 创建另一个变量,并赋给它一个字符串(某个文本)。然后使用 print 显示这个变量。

4. 像上一章一样,在交互模式中让 Python 计算一周有多少分钟。不过,这一次要使用变量。以 DaysPerWeek(每周天数)、HoursPerDay(每天小时数)和 MinutesPerHour(每小时分钟数)为名分别创建变量(或者也可以用自己取的变量名),然后将它们相乘。

5. 人们总是说没有足够的时间做到尽善尽美。如果一天有 26 个小时,那么一周会有多少分钟呢?(提示:改变 HoursPerDay 变量。)

目录

  • 版权声明
  • 对本书第 1 版的赞誉
  • 对本书第 2 版的赞誉
  • 推荐序一
  • 推荐序二
  • 第 1 版译者序
  • 前言
  • 关于本书
  • 第 1 版致谢
  • 第 2 版致谢
  • 第 1 章 出发吧
  • 第 2 章 记住内存和变量
  • 第 3 章 基本数学运算
  • 第 4 章 数据的类型
  • 第 5 章 输入
  • 第 6 章 GUI——图形用户界面
  • 第 7 章 判断再判断
  • 第 8 章 转圈圈
  • 第 9 章 全都为了你——注释
  • 第 10 章 游戏时间到了
  • 第 11 章 嵌套与可变循环
  • 第 12 章 收集起来——列表与字典
  • 第 13 章 函数
  • 第 14 章 对象
  • 第 15 章 模块
  • 第 16 章 图形
  • 第 17 章 动画精灵和碰撞检测
  • 第 18 章 一种新的输入——事件
  • 第 19 章 声音
  • 第 20 章 更多 GUI
  • 第 21 章 打印格式化与字符串
  • 第 22 章 文件输入与输出
  • 第 23 章 碰运气——随机性
  • 第 24 章 计算机仿真
  • 第 25 章 Skier 游戏的说明
  • 第 26 章 Python Battle
  • 第 27 章 接下来呢
  • 附录 A 变量命名规则
  • 附录 B Python 2 与 Python 3 的差异
  • 附录 C 自测题答案