0.2. PY4E - Python 为所有人¶
切换导航
第 1 章:简介 第 2 章:变量 第 3 章:条件语句 第 4 章:函数 第 5 章:迭代 第 6 章:字符串 第 7 章:文件 第 8 章:列表 第 9 章:字典 第 10 章:元组 第 11 章:正则表达式 第 12 章:网络程序 第 13 章:Python 与 Web 服务 第 14 章:Python 对象 第 15 章:Python 与数据库 第 16 章:数据可视化
0.3. 变量、表达式和语句¶
0.3.1. 值与类型¶
一个 value 是程序处理的基本对象之一,比如一个字母或一个数字。我们到目前为止看到的值是 1、2 和 "Hello, World!"
这些值属于不同的 类型:2 是一个整数,而 "Hello, World!" 是一个 字符串,之所以称为字符串是因为它包含一串字母。你(以及解释器)可以通过它们被引号包围来识别字符串。
之前的 print 语句也适用于整数。我们使用 python 命令来启动解释器。
python
>>> print(4)
4
如果您不确定某个值的类型,解释器可以告诉您。
>>> type('Hello, World!')
<class 'str'>
>>> type(17)
<class 'int'>
不出所料,字符串属于类型 str,而整数属于类型 int。不那么显而易见的是,带有小数点的数字属于一种称为 float 的类型,因为这些数字是以称为 floating point 的格式表示的。
>>> type(3.2)
<class 'float'>
那像"17"和"3.2"这样的值呢?它们看起来像数字,但它们在引号内,就像字符串一样。
>>> type('17')
<class 'str'>
>>> type('3.2')
<class 'str'>
它们是字符串。
当你输入一个大整数时,你可能会想在每三位数字之间使用逗号,例如 1,000,000。这在 Python 中不是合法的整数,但是合法的:
>>> print(1,000,000)
1 0 0
嗯,这完全不是我们预期的!Python 将 1,000,000 解释为逗号分隔的整数序列,并以空格分隔的方式打印出来。
这是我们见过的第一个语义错误示例:代码运行不会产生错误消息,但它没有做“正确”的事情。
0.3.2. 变量¶
编程语言最强大的功能之一是能够操作 变量。变量是一个引用值的名称。
赋值语句创建新变量并赋予它们值:
>>> message = 'And now for something completely different'
>>> n = 17
>>> pi = 3.1415926535897931
本示例进行了三次赋值。第一次将字符串赋值给名为 `message` 的新变量;第二次将整数 17 赋值给 `n`;第三次将 π 的(近似)值赋值给 `pi`。
要显示变量的值,你可以使用 print 语句:
>>> print(n)
17
>>> print(pi)
3.141592653589793
变量的类型是指它引用的值的类型。
>>> type(message)
<class 'str'>
>>> type(n)
<class 'int'>
>>> type(pi)
<class 'float'>
0.3.3. 变量名和关键字¶
程序员通常会为他们的变量选择有意义的名称,并记录变量用途。
变量名可以任意长。它们可以包含字母和数字,但不能以数字开头。使用大写字母是合法的,但以小写字母开头变量名是个好主意(稍后你会明白为什么)。
下划线字符 ( _ ) 可以出现在名称中。它常用于多词名称中,例如 my_name 或 airspeed_of_unladen_swallow。变量名称可以以下划线字符开头,但我们通常避免这样做,除非我们正在编写供他人使用的库代码。
如果给变量一个非法名称,你会得到一个语法错误:
>>> 76trombones = 'big parade'
SyntaxError: invalid syntax
>>> more@ = 1000000
SyntaxError: invalid syntax
>>> class = 'Advanced Theoretical Zymurgy'
SyntaxError: invalid syntax
76trombones 是非法的,因为它以数字开头。more@ 是非法的,因为它包含非法字符 @。但 class 有什么问题呢?
事实证明,class 是 Python 的一个 关键字。解释器使用关键字来识别程序的结构,因此它们不能用作变量名。
Python 保留 35 个关键字:
and del from None True
as elif global nonlocal try
assert else if not while
break except import or with
class False in pass yield
continue finally is raise async
def for lambda return await
您可能希望将此列表放在手边。如果解释器抱怨您的某个变量名,而您不知道原因,请查看它是否在此列表中。
0.3.4. 语句¶
一个 语句 是 Python 解释器可以执行的代码单元。我们已经见过两种类型的语句:print 是一个表达式语句,而赋值则是另一种。
当您在交互模式下输入语句时,解释器会执行它并显示结果(如果有)。
脚本通常包含一系列语句。如果存在多个语句,结果将随着语句的执行逐个出现。
例如,该脚本
print(1)
x = 2
print(x)
产生输出
1
2
赋值语句不产生任何输出。
0.3.5. 运算符和运算对象¶
运算符 是表示诸如加法和乘法等运算的特殊符号。运算符所作用到的值称为 操作数。
运算符 +、-、*、/ 和 ** 分别执行加法、减法、乘法、除法和幂运算,如下例所示:
20+32
hour-1
hour*60+minute
minute/60
5**2
(5+9)*(15-7)
Python 2.x 与 Python 3.x 之间的除法运算符发生了变化。在 Python 3.x 中,该除法运算的结果为浮点数结果:
>>> minute = 59
>>> minute/60
0.9833333333333333
Python 2.0 中的除法运算符会将两个整数相除并将结果截断为整数:
>>> minute = 59
>>> minute/60
0
为在 Python 3.0 中获得相同的答案,请使用向下取整(// 整数)除法。
>>> minute = 59
>>> minute//60
0
在 Python 3.0 中,整数除法函数的行为与你预期在计算器中输入表达式时的行为非常一致。
0.3.6. 表达式¶
一个 表达式 是值、变量和运算符的组合。单独一个值被视为表达式,变量也是如此,因此以下内容都是合法的表达式(假设变量 x 已被赋予一个值):
17
x
x + 17
如果在交互模式下输入表达式,解释器会 评估 它并显示结果:
>>> 1 + 1
2
但在脚本中,单独一个表达式不会做任何事情!这是初学者常见的困惑来源。
练习 1:在 Python 解释器中键入以下语句,以查看它们的作用:
5
x = 5
x + 1
0.3.7. 运算顺序¶
当表达式中出现多个运算符时,求值顺序取决于 运算优先级规则。对于数学运算符,Python 遵循数学惯例。缩写词 PEMDAS 是记忆这些规则的一种有用方法:
P括号具有最高优先级,可用于强制表达式按照您期望的顺序求值。由于括号内的表达式会首先被求值,因此
2 * (3-1)为 4,而(1+1)**(5-2)为 8。您还可以使用括号使表达式更易阅读,例如(minute * 100) / 60,即使它不改变结果。E指数运算的优先级次于括号,因此
2**1+1是 3 而非 4,3*1**3是 3 而非 27。M乘法与 D除法具有相同优先级,且高于 A加法与 S减法(它们的优先级也相同)。因此
2*3-1是 5 而非 4,6+4/2是 8 而非 5。相同优先级的运算符从左到右求值。因此表达式
5-3-1的值为 1 而非 3,因为5-3先发生,随后将1从 2 中减去。
如有疑问,请在表达式中始终使用括号,以确保计算按照您的预期顺序执行。
0.3.8. 取模运算符¶
取模运算符作用于整数,并返回第一个操作数除以第二个操作数后的余数。在 Python 中,取模运算符是百分号(%)。其语法与其他运算符相同:
>>> quotient = 7 // 3
>>> print(quotient)
2
>>> remainder = 7 % 3
>>> print(remainder)
1
所以 7 除以 3 等于 2,余 1。
取模运算符的结果出乎意料地有用。例如,你可以检查一个数是否可被另一个数整除:如果 x % y 为零,那么 x 可被 y 整除。
您也可以从数字中提取最右边的数字或几位数字。例如,x % 10 生成 x 的最右边数字(十进制)。同样,x % 100 生成最后两位数字。
0.3.9. 字符串操作¶
+ 运算符可用于字符串,但它并非数学意义上的加法。相反,它执行 连接 操作,即将字符串首尾相接。例如:
>>> first = 10
>>> second = 15
>>> print(first+second)
25
>>> first = '100'
>>> second = '150'
>>> print(first + second)
100150
* 运算符也可用于字符串,通过将字符串内容乘以整数。例如:
>>> first = 'Test '
>>> second = 3
>>> print(first * second)
Test Test Test
0.3.10. 向用户请求输入¶
有时我们希望通过用户的键盘获取变量的值。Python 提供了一个名为 input() 的内置函数 input 来获取键盘输入:sup:`1 <https://www.py4e.com/html3/02-variables#fn1>`__。当调用此函数时,程序会停止并等待用户输入内容。当用户按下 Return 或 Enter 键时,程序恢复执行,且 input 将用户输入的内容作为字符串返回。
>>> inp = input()
Some silly stuff
>>> print(inp)
Some silly stuff
在从用户获取输入之前,打印一个提示告诉用户需要输入什么内容是一个好主意。你可以将一个字符串传递给 input,以便在暂停以获取输入之前显示给用户:
>>> name = input('What is your name?\n')
What is your name?
Chuck
>>> print(name)
Chuck
提示末尾的序列 \n 代表一个 换行符,这是一个导致换行的特殊字符。这就是为什么用户的输入会显示在提示符下方。
如果您预期用户输入一个整数,您可以尝试使用 int() 函数将返回值转换为 int:
>>> prompt = 'What...is the airspeed velocity of an unladen swallow?\n'
>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
17
>>> int(speed)
17
>>> int(speed) + 5
22
但如果用户输入的不是数字字符串,则会报错:
>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
What do you mean, an African or a European swallow?
>>> int(speed)
ValueError: invalid literal for int() with base 10:
我们稍后将看到如何处理此类错误。
0.3.11. 注释¶
随着程序变得更大且更复杂,它们变得更难阅读。形式化语言非常密集,而且往往很难通过查看一段代码来弄清楚它在做什么,或者为什么。
由于此原因,在程序中用自然语言添加注释来解释程序正在做什么是个好主意。这些注释称为 注释,在 Python 中它们以 # 符号开头:
# compute the percentage of the hour that has elapsed
percentage = (minute * 100) / 60
在这种情况下,注释单独出现在一行。你也可以在行尾添加注释:
percentage = (minute * 100) / 60 # percentage of an hour
行中从 `#` 到行尾的所有内容均被忽略;它不会影响程序。
注释在记录代码中非显而易见的特性时最为有用。可以合理地假设读者能够理解代码 做什么;解释 为什么 则更有用。
此注释与代码重复且无用:
v = 5 # assign 5 to v
此注释包含代码中未有的有用信息:
v = 5 # velocity in meters/second.
良好的变量名可以减少对注释的需求,但过长的名称会使复杂的表达式难以阅读,因此需要在两者之间取得平衡。
0.3.12. 选择助记变量名¶
只要遵循变量命名的简单规则,并避免使用保留字,您在命名变量时就有多种选择。在开始时,这种选择在读程序或编写自己的程序时都可能令人困惑。例如,以下三个程序在功能上是相同的,但在阅读和理解时却大不相同。
a = 35.0
b = 12.50
c = a * b
print(c)
hours = 35.0
rate = 12.50
pay = hours * rate
print(pay)
x1q3z9ahd = 35.0
x1q3z9afd = 12.50
x1q3p9afd = x1q3z9ahd * x1q3z9afd
print(x1q3p9afd)
Python 解释器认为这三个程序 完全相同,但人类看待和理解这些程序的方式却大不相同。人类会最快地理解第二个程序的 意图,因为程序员选择的变量名反映了他们关于将在每个变量中存储什么数据的意图。
我们称这些精心选择的变量名为“助记变量名”。单词 mnemonic :sup:`2 <https://www.py4e.com/html3/02-variables#fn2>`__ 意为“记忆辅助”。我们选择助记变量名是为了帮助我们记住最初创建该变量的原因。
虽然这一切听起来都很棒,而且使用助记变量名是一个非常好的想法,但助记变量名可能会妨碍初学程序员解析和理解代码的能力。这是因为初学程序员尚未记住保留字(只有 33 个),而且有时名称过于描述性的变量开始看起来像是语言的一部分,而不仅仅是精心选择的变量名。
快速浏览以下 Python 示例代码,该代码遍历了一些数据。我们很快就会讲解循环,但现在试着理解这段代码的含义:
for word in words:
print(word)
这里发生了什么?哪些标记(for、word、in 等)是保留字,哪些仅仅是变量名?Python 在根本上是否理解单词的概念?初学编程者难以区分代码中哪些部分 必须 与示例相同,哪些部分仅仅是程序员做出的选择。
下面的代码与上面的代码等价:
for slice in pizza:
print(slice)
对于初学者来说,查看这段代码并分辨哪些部分是 Python 定义的保留字,哪些部分仅仅是程序员选择的变量名,会更加容易。很明显,Python 并不真正理解披萨和切片,也不理解披萨由一个或多个切片组成的这一事实。
但如果我们的程序真正是关于读取数据并在数据中查找单词,那么 `pizza` 和 `slice` 是非常不助记的变量名。将它们选为变量名会分散人们对程序含义的注意力。
经过一段相当短的时间后,您将知道最常见的保留字,并且您将开始注意到这些保留字跃然纸上:
for word in words:
print(word)
代码中由 Python 定义的组成部分(for, in, print, 和 :)以粗体显示,而程序员选择的变量(word 和 words)未以粗体显示。许多文本编辑器了解 Python 语法,会以不同颜色突出显示保留字,从而为您提供线索,帮助您将变量与保留字区分开来。一段时间后,您将开始阅读 Python 并迅速判断出哪些是变量,哪些是保留字。
0.3.13. 调试¶
此时,你最容易犯的错误是非法的变量名,例如 class 和 yield,它们是关键字,或者 odd~job 和 US$,它们包含非法字符。
如果在变量名中放入一个空格,Python 会认为这是两个没有运算符的操作数:
>>> bad name = 5
SyntaxError: invalid syntax
>>> month = 09
File "<stdin>", line 1
month = 09
^
SyntaxError: invalid token
对于语法错误,错误信息并没有太大帮助。最常见的消息是 SyntaxError: invalid syntax 和 SyntaxError: invalid token,其中两者都不是很具信息量。
你最可能遇到的运行时错误是“先使用后定义”,即在你尚未赋值的情况下尝试使用变量。这可能会发生在你拼错变量名时:
>>> principal = 327.68
>>> interest = principle * rate
NameError: name 'principle' is not defined
变量名是区分大小写的,因此 LaTeX 与 latex 不相同。
此时,语义错误最可能的原因是运算顺序。例如,为了计算 1/2π,您可能想写成
>>> 1.0 / 2.0 * pi
但是除法运算优先执行,因此你会得到 π/2,这与预期不同!Python 无法知晓你的本意,因此在这种情况下不会出现错误提示;你只会得到错误的答案。
0.3.14. 术语表¶
赋值 将值赋给变量的语句。连接 将两个操作数首尾相接。注释 程序中供其他程序员(或任何阅读源代码的人)使用的信息,对程序的执行没有影响。求值 通过按顺序执行运算来简化表达式,以得出单个值。表达式 由变量、运算符和值组合而成,表示单个结果值。浮点数 表示带小数部分的数字的类型。整数 表示整数的类型。关键字 编译器用于解析程序的保留字;你不能像使用 if、def 和 while 那样将关键字用作变量名。助记符 记忆辅助。我们经常给变量起助记符名称,以帮助记住变量中存储的内容。取模运算符 用百分号(%)表示的运算符,作用于整数,并得出一个数除以另一个数时的余数。操作数 运算符所作用的一个值。运算符 表示简单运算(如加法、乘法或字符串连接)的特殊符号。运算优先级 控制涉及多个运算符和操作数的表达式求值顺序的规则集。语句 代表命令或操作的代码段。到目前为止,我们看到的语句是赋值语句和 print 表达式语句。字符串 表示字符序列的类型。类型 值的类别。到目前为止,我们见过的类型包括整数(类型 int)、浮点数(类型 float)和字符串(类型 str)。值 数据的基本单元之一,如数字或字符串,是程序所操作的。变量 指代值的名称。
0.3.15. 练习¶
练习 2:编写一个程序,使用 ``input`` 提示用户输入姓名,然后欢迎他们。
Enter your name: Chuck
Hello Chuck
练习 3:编写一个程序,提示用户输入小时数和每小时费率,以计算总工资。
Enter Hours: 35
Enter Rate: 2.75
Pay: 96.25
暂时我们不会担心确保我们的工资在十进制点后恰好有两位数字。如果你愿意,可以使用内置的 Python round 函数来将计算出的工资正确地四舍五入到两位小数。
练习 4:假设我们执行以下赋值语句:
width = 17
height = 12.0
对于下列每个表达式,写出表达式的值以及类型(表达式的值的类型)。
width//2width/2.0height/31 + 2 * 5
使用 Python 解释器检查您的答案。
练习 5:编写一个程序,提示用户输入摄氏温度,将其转换为华氏温度,并打印转换后的温度。
在 Python 2.0 中,该函数名为
raw_input。↩︎参见 https://en.wikipedia.org/wiki/Mnemonic 获取关于单词 "mnemonic" 的详细描述。↩︎
如果您在本书中发现错误,请随时使用 Github 向我发送修复方案。
