三、内存和变量

什么是程序?程序就是下达给计算机的一系列指令。

  1. 接受输入(input)
  2. 处理输入(process)
  3. 产生输出(output)

输入、处理、输出

前面的猜数游戏就具备以下这三个基本要素:

  • 输人:玩家键入的数,也就是他猜的数。
  • 处理:程序检查玩家猜的数,并统计已经猜过几次。
  • 输出:程序最后打印的消息。

再给一个例子:
Python 基础 - 图1

  • 输入:来自操纵杆或游戏控制器的信号。
  • 处理:程序确定你是否击中外星人、避开火球、顺利过关或者做其他活动。
  • 输出:屏幕上显示的图形和扬声器或耳机传出的声音。

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

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

名字

创建一个由字母”Mr. Pitt”组成的东西,并且给它起了一个名字 teacher。这里的等号(=)告诉 Python 要赋值(assign)或者“让……等于……”。这里把字母序列 “Mr. Pitt” 赋值给名字 teacher。

  1. teacher = 'Mr. Pitt'
  2. print(teacher)

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

把一个值赋给一个名字时(如把值“Mr. Pitt”赋给teacher),它会存储在内存中,称为变量(variable)。在大多数编程语言中,都把这称为“把值存储(store)在变量中”。不过Python与大多数其他计算机语言的做法稍有不同。它并不是把值存储在变量中,而更像是把名字放在值上。

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

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

除了字母,还可以为其他内容创建变量。可以给数值指定名字。

  1. >>> First = 5
  2. >>> Second = 3
  3. >>> print(First + Second)
  4. 8
  5. >>> Third = First + Second
  6. >>> Third
  7. 8

取 First 的值和 Second 的值,将二者相加,创建一个新的值,名为 Third。Third 是 First 和 Second 的和。
image.png

变量名的规则

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

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

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

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

  1. xblahbl2blahblah = 'Mr. Pitt'
  2. t = 'Mr. Pitt'
  3. teacher = 'Mr. Pitt'
  4. my_teacher = 'Mr. Pitt'

数字和字符串

字符或字符序列(字母、数字或标点符号)称为一个字符串(string)。在字符两边加上引号就创建一个字符串。单引号和双引号都是可以的。

如果键入一个数字而没有加引号,Python 就会知道这表示数值,而不是字符。

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

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

变量的赋值

Python 是一门弱类型语言,弱类型包含两方面的含义:

  1. 所有的变量无须声明即可使用,或者说对从未用过的变量赋值就是声明了应变量;
  2. 变量的数据类型可以随时改变,同一个变量可以一会儿是数值型,一会儿是字符串型。

创建了一个新东西 “Mr. Smith”,并把它命名为 Teacher。把旧标签(名字)从原来的值上取下来,贴到了这个新东西上。就叫赋值。

不过原来的 “Mr. Morton” 怎么样了呢?一个东西可以有多个名字(上面可以贴多个标签)。如果 “Mr. Morton” 上还有另一个标签,那么它还在计算机的内存里。

如果它上面再没有任何标签了,Python 就会发现再没有人需要它了,所以会把它从内存中删除。这样一来,内存中就不会塞满那些没人用的东西。Python 会自动完成所有这些清理工作,根本不用我们操心。

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

自增

要让变量等于某个东西,这个变量总会出现在等号 (=) 左边。巧妙的是,变量也可以出现在等号右边。最常见的用法是让变量自增(increment),也就是让它增加某个量,或者与之相反,也可以让变量自减(decrement),让它减少某个量。

  1. score = 7
  2. score = score + 1
  3. score += 1
  4. score = score - 2
  5. score -= 2

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

Revision

  • 如何使用变量在计算机内存中“记住”或保存信息。
  • 变量也叫做“名字”或“变量名”。
  • ˆˆ变量可以是不同类型的东西,如数字和字符串。

测试题

  1. 如何告诉 Python 变量是字符串(字符)而不是数字?
  2. 一旦创建一个变量,能不能改变赋给这个变量的值?
  3. 变量名 TEACHER 与 TEACHEr 相同吗?
  4. 对 Python 来说,’Blah’ 与 “Blah” 一样吗?
  5. 对 Python 来说,’4’ 是不是等同于 4 ?
  6. 下面哪个变量名不正确?为什么?
  7. Teacher2
  8. 2Teacher
  9. teacher_25
  10. TeaCher
  11. “10” 是数字还是字符串?

动手试一试

  1. 创建一个变量,并给它赋一个数值(任何数值都行)。然后使用 print 显示这个变量。
  2. 改变这个变量,可以用一个新值替换原来的值,或者将原来的值增加某个量。 使用 print 显示这个新值。
  3. 创建另一个变量,并赋给它一个字符串(某个文本)。然后使用 print 显示这个变量。
  4. 像上一章一样,在交互模式中让 Python 计算一周有多少分钟。不过,这一次要使用变量。以 DaysPerWeek(每周天数)、HoursPerDay(每天小时数) 和 MinutesPerHour(每小时分钟数)为名分别创建变量(或者也可以用自己取 的变量名),然后将它们相乘。
  5. 人们总是说没有足够的时间做到尽善尽美。如果一天有 26 个小时,那么一周 会有多少分钟呢?(提示:改变 HoursPerDay 变量。)

四、数据类型

Python 里面万物皆对象(object),整型也不例外,只要是对象,就有相应的属性(attributes)和方法(methods)。

  • 逻辑变量: True, False
  • 数值: 整型, 浮点数, 复数
  • 字符串
  • 列表(list), 元组(tuple)和字典 (dict)

type()

我们通过看引号来确定一个值究竟是数还是字符串。要确定它是一个数还是字符串还有一种更直接的方法。Python 提供了函数 type(),它可以明确地告诉我们变量的类型。

  1. >>> a = '44.2'
  2. >>> b = 44.2
  3. >>> type(a)
  4. <type 'str'>
  5. >>> type(b)
  6. <type 'float'>

类型转换

Python 实际上并没有把一个东西从一种类型“转换”成另一种类型。它只是由原来的东西创建一个新东西,而且这个新东西正是你想要的类型。下面给出一些函数,它们可以把数据从一种类型转换为另一种类型:

  • ˆˆfloat() 从一个字符串或整数创建一个新的浮点数(小数)。
  • ˆˆint() 从一个字符串或浮点数创建一个新的整数。
  • ˆˆstr() 从一个数(可以是任何其他类型)创建一个新的字符串。

把你想要转数据的类型换的值放在函数后面的小括号里。

  1. >>> a = 24
  2. >>> b = float(a)
  3. >>> a
  4. 24
  5. >>> b
  6. 24.0
  7. >>> c = 38.0
  8. >>> d = int(c)
  9. >>> c
  10. 38.0
  11. >>> d
  12. 38
  13. >>> e = 54.99
  14. >>> f = int(e)
  15. >>> print(e)
  16. 54.99
  17. >>> print(f)
  18. 54

image.png

十进制转二进制

  1. >>> bin(9)
  2. '0b1001'

十转八

  1. >>> oct(9)
  2. '0o11'

十转十六

  1. >>> hex(19)
  2. '0x13'

类型转换错误

如果向 int()float() 提供的不是一个数,它就会不正常。下面来试试看:

  1. >>> print(float('fred'))
  2. Traceback (most recent call last) :
  3. File "<pyshe11#1>", line 1in <module>
  4. print(float(' fred'))
  5. ValueError: could not convert string to float: fred

我们得到了一个错误消息。这个非法文字(invalid literal)错误消息说明 Python 不知道怎么从 “fred” 创建一个数。如果是你,你知道吗?

浮点数的精度

  1. >>> 2.99999999
  2. 2.99999999
  3. >>> 2.999999999999999999
  4. 3.0

string 和 bytes

python3 最重要的新特性大概要算对文本和二进制数据做了更为清晰的区分,文本总是 unicode 字符集,有 str 类型表示,二进制数据则有 bytes 类型表示。python3 不会以任何隐式的方式混用 strbytes ,这两者的区别特别明显,你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然);

我们不关心字符串在内部是如何被表示的,也不关心它用几个字节来表示每个字符。只有在将字符串编码成字节(如用于通信信道的传输)或将字节解码成字符串时,才考虑这些问题。
image.png

编码可以将抽象字符以二进制数据的形式表示,有很多编码方法,如 utf-8gbk 等,可以使用 encode() 函数对字符串进行编码,转换成二进制字节数据,也可用 decode() 函数将字节解码成字符串

  1. a = bytes([1,2,3,4])
  2. a = bytes('hello', 'ascii')
  3. b = a.encode(encoding='utf-8')
  4. c = b.decode(encoding='utf-8')

Bool 类型

false.jpg

all()

判断元素是否都为真

  1. >>> all([1,0,3,6])
  2. False
  3. >>> all([1,1,3,6])
  4. True

any()

判断是否至少有一个元素为真

  1. >>> any([0,0,0,[]])
  2. False
  3. >>> any([0,0,1])
  4. True

缓存重用机制

Revision

  • 完成类型转换(或者更准确地说,从某些类型创建另外-些类型):str()int ()float()
  • 直接显示值,而不使用 print
  • 使用 type() 查看变量的类型。
  • 舍入误差及其出现的原因。

测试题

  1. 使用 int() 将小数转换为整数,结果是上取整还是下取整?
  2. 在温度转换程序中,可以这样做吗?

    1. cel = float(5 // 9 * (fahr – 32))

    这样呢?如果不行,为什么?

    1. cel = 5 / 9 * float(fahr 32)
  3. (挑战题)除了 int() 不使用任何其他函数,如何对一个数四舍五入而不是下取整?(例如,13.2 会下取整为 13,但是 13.7 会上取整为 14。)

动手试一试

  1. 使用 float() 从一个字符串(如 ‘12.34’)创建一个数。要保证结果确实是一个数!
  2. 试着使用 int() 从一个小数(56.78)创建一个整数。答案是上取整还是下取整?
  3. 试着使用 int() 从一个字符串创建整数。要保证结果确实是一个整数!

五、输入

一个程序有 3 大部分:输入、处理和输出。我们的第一个程序只有输出。温度转换程序有处理(转换温度)和输出,但是没有输入。现在该向程序增加第三个部分了:输入。输入就是指在程序运行时向其提供某样东西,也就是某种信息。

input()

input() 函数从用户那里得到一个字符串。正常情况下会从键盘得到这个输入,也就是说,用户要键入输入。

  1. print("Enter your name: ")
  2. somebody = input()
  3. print("Hi" + somebody + ", how are you today?")
  1. somebody = input("Enter your name: ")
  2. print("Hi" + somebody + ", how are you today?")

输入数字

我们已经见过如何使用 input() 来得到字符串。但是如果希望得到一个数该怎么做呢?可以从 input() 给我们的字符串使用 int()float() 函数创建一个数。

  1. temp_string = input()
  2. fahrenheit = float(temp_string)
  3. #一步到位的写法
  4. fahrenheit = float(input())

温度转换程序

  1. print("This program converts Fahrenheit to Celsius")
  2. print("Type in a temperature in Fahrenheit: ")
  3. fahrenheit = float(input())
  4. celsius = (fahrenheit 32) * 5.0 / 9
  5. print("That is" + str(celsius) + "degrees Celsius")

来自互联网的输入

通常,程序的输入都来自用户。不过还有其他一些方法得到输入。可以从计算机硬盘上的文件中得到输入,或者也可以从互联网获取输入。

  1. import urllib.request as request
  2. file = request.urlopen('http://helloworldbook2.com/data/message.txt')
  3. message = file.read()
  4. print(message.decode(encoding='utf-8'))

revision

  • ˆˆ用 input() 输入文本。
  • ˆˆ向 input() 增加一个提示消息。
  • ˆˆ结合 int()float() 使用 input() 输入数字。

ˆˆ

测试题

  1. 对于下面这行代码:answer = input()
    1. 如果用户键入 12,answer 的数据类型是什么?是字符串还是一个数?
  2. 怎么让 input() 打印一个提示消息?
  3. 怎么使用 input() 得到一个整数?
  4. 怎么使用 input() 得到一个浮点数(小数)?

动手试一试

  1. 在交互模式中建立两个变量,分别表示你的姓和名。然后使用一条 print 语句,把姓和名打印在一起。
  2. 编写一个程序,先问你的姓,再问名,然后打印一条消息,在消息中包含你的姓和名。
  3. 编写一个程序询问一间长方形房间的尺寸(单位是米),然后计算覆盖整个房间总共需要多少地毯,并显示出来。
  4. 编写一个程序先完成第 3 题的要求,不过还要询问每平方尺地毯的价格。然后主程序显示下面 3 个内容:
    1. 总共需要多少地毯,单位是平方米。
    2. 总共需要多少地毯,单位是平方尺(1 平方米 = 9 平方尺)。
    3. 地毯总价格。
  5. 编写一个程序帮助用户统计她的零钱。程序要问下面的问题。让程序给出这些零钱的总面值。
    1. 有多少个五分币?
    2. 有多少个二分币?
    3. 有多少个一分币?

六、注释

到现在为止,我们在程序(以及交互模式)中键入的所有一切都是交给计算机的指令。不过,还可以在程序中为你自己加入一些说明,描述这个程序做什么,怎么做,这是一个很好的想法。这样能够帮助你(或者其他人)以后查看程序,了解原先你想做什么。

在计算机程序中,这些说明就称为注释(comment)。注释是程序文档的一部分,计算机运行程序时会忽略这些注释。

单行注释

在任何代码行前面加上 # 符号就可以把它变成一个注释。(这个符号叫做数字符号,有时也叫做镑符号。)

  1. #这是Python程序中的一个注释
  2. print('This is not a comment')

行末注释

还可以在一行代码的最后加注释,像下面这样:

  1. area = length * width #计算矩形的面积

注释从 # 字符开始。# 之前的所有内容都是正常的代码行,在它后面的所有内容则是注释。

多行注释

有时你可能想使用多行注释。可以使用多行,每行前面都有一个 # 字符,像下面这样:

  1. # ***************
  2. # 这个程序用来说明Python中如何使用注释
  3. # 星号所在的行只为将注释
  4. # 与其余代码清楚地区分开
  5. # ***************

多行注释可以很好地“突出”代码段,使你读代码时能清楚地区分不同代码段。可以用多行注释来描述一段代码要做什么。

三重引号字符串是一个可以跨多行的字符串。所以可以这样写:

  1. """
  2. 这是一个包括多行的注释,
  3. 使用了三重引号字符串。
  4. 这不完全是注释,不过也可以
  5. 相当于注释。
  6. """

因为这个字符串没有名字,而且程序对这个字符串不“做”任何处理,所以它对程序的运行没有任何影响,它相当于一个注释。

Revision

  • ˆˆ注释只是为了方便你(和其他人),而不是用来帮助计算机。
  • 注释还可以用来隔离部分代码,不让它们运行。
  • ˆˆ可以使用三重引号字符串作为一种跨多行的注释。

测试题

由于注释相当简单,所以我们可以休息一下,这一章没有测验题。

动手试一试

再来看看之前的温度转换程序,增加一些注释。重新运行程序,看看运行结果是不是还一样。