本节书摘来自华章计算机《从问题到程序:用Python学编程和计算》一书中的第2章,第2.10节,作者 裘宗燕,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.10 若干Python机制及其他
作为本章最后一节,这里先简单地回顾一下已经讨论的Python基本机制和相关编程技术,然后介绍若干前面没有讨论的Python功能。
2.10.1 已讨论的Python机制
首先总结一下已经讨论过的基本语句,它们用于描述基本操作:
- 赋值语句。这是最常用的基本语句。
- 表达式语句。可以在一个程序行中只写一个表达式,可以是任何计算表达式,最常见的是函数调用(如调用print。函数调用是表达式)。执行时解释器求值该表达式。如果在交互方式中求值,解释器将显示得到的结果;在非交互方式下,解释器求值这种表达式之后,就简单地把结果抛弃。
- break、continue、return语句,用于循环控制或函数返回值。
- import语句,用于导入程序包里提供的功能。
除了这些简单语句外,Python还提供了一组用于控制语句执行进程的结构语句,包括if、for和while。它们是复合语句,因为它们都包含一个、两个或多个作为成分的语句,其执行中的主要行为就是控制这个(这些)成分语句的执行。
另一主要机制是def语句,这种语句的执行将建立起一个函数(注意,在Python里函数也是对象,称为函数对象),并将其约束于def语句中给定的函数名。一个函数包装起一段称为函数体的程序代码。一个函数定义被执行后(函数定义好之后),就可以通过该函数的名字调用所定义的函数了。在函数体里可以写任何语句,包括调用其他函数。
这些就是Python的基本编程机制,本书后面的大部分内容都围绕着这些机制的使用,讨论关于如何使用它们去解决各种计算问题。今后讨论中展示的实例多为函数定义,其使用和结果则较少给出,以节约篇幅。由于本书提供了所有实例程序代码,所定义函数的具体执行留给读者自己完成。
2.10.2 若干Python机制
在继续研究编程和用编程的方式解决问题之前,现在介绍几种前面没有讨论的编程机制。这些机制都不是根本性的,没有它们也能写出所有的程序。但这些机制在一些情况中很有用,有些就是为了简化程序的书写。
pass语句
pass语句也是一种基本语句,形式上只包含关键字pass。这个语句执行时什么也不做,立即结束。这种语句的作用类似于整数中的0、字符串中的空串等,表示某种最基本的情况。在实际程序里,pass语句通常用于填补语法结构。如果某种结构要求一个语句成分,但实际程序中不需要做任何操作,就可以用pass填补空白。
扩展赋值运算符
赋值语句还有扩展的形式,下面两种也比较常用:
第一种形式用于把一个表达式的值赋给多个变量(可以有任意多个,其中的 …… 表示其他变量)。这种赋值语句同样要求先求出表达式的值,而后把该值赋给左边的所有变量。第二种形式要求把一串表达式的值分别赋给一串变量,这里要求变量和表达式的个数相同,解释器将顺序求值各个表达式,然后按位置给对应的变量赋值。
由于程序中经常需要写诸如n = n + 1或x = x 2一类语句,也就是说,基于一个变量的原值,用一个运算算出新值,最后用这个新值更新变量。具体的例子如前面fact函数里的prod = prod k等。在这种描述中,被使用和更新的变量出现了两次。后面还会看到,变量还有更复杂的描述形式,减少这种重复书写也有价值。
为处理这个问题,Python提供了一组扩展赋值符,其功能相当于做一次二元运算,再用运算结果更新变量。针对每个二元运算符各有一个组合赋值符:
这些操作的作用都是原地更新,即,直接修改这些赋值符左边的变量。最后几个运算符没有合适的名字,写出的名字只供参考,后面讨论中也不会使用。举两个例子:从效果看,prod = k就相当于prod = prod k;语句n += 1的效果是使变量n的值比语句之前增加了1。用这些赋值符写出的语句也作为赋值语句看待。
上述运算符很有用,例如前面的阶乘函数现在可以重新写为:
def fact(n):
prod = 1
for k in range(2, n+1):
prod *= k
return prod
上面说,例如,prod = k与prod = prod k等价,这是从语义效果讲。但解释器完全可以对一些情况采用更优异的实现方法。例如,许多硬件有更新寄存器的专门指令,如果解释器利用它们,前者的效率可能更高。因此,如果要做基于变量原值的更新,而某个扩展赋值运算符正好合用,就应该使用它。书写上更简单,意义更明确清晰,还可能执行效率更高,何乐而不为呢?
请读者检查前面的程序实例,看看哪些程序可以改用这些赋值符。在后面章节里,很多地方都可以看待这类赋值符的使用。
条件表达式
Python还有一种特殊的带条件的表达式,用于描述在不同情况下采用不同规则求值的情况。条件表达式也是表达式,每个条件表达式计算出一个值。
条件表达式的形式是:
其中条件部分描述某种逻辑关系。这种表达式的语义(求值的方式)是:首先求值条件,如果其值为真就求值表达式1,以其值作为整个条件表达式的值;当条件不真时求值表达式2,并以其值作为整个表达式的值。
下面是基于条件表达定义的求绝对值函数:
def abs(x):
return x if x >= 0 else -x
定义很简单。虽然abs是内置函数名,但这个标识符并不是关键字,这里重新定义也是合法的。当然,这里只是作为例子,实际中人们一般不这样做。
有关条件表达式,有两个问题需要注意。首先,如果求值一个条件表达式,其两个成分表达式中只有一个会被实际求值。例如,下面语句不会出现除0错误:
z = y/x if x != 0 else y/(x + 1)
还应注意条件表达式与条件语句的不同。语句没有值,执行时产生“效果”,表达式的计算就是求值。用条件语句定义abs函数,应写为:
def abs(x):
if x >= 0:
return x
else:
return x
比较一下,用条件表达式写出的定义更紧凑。在方便的时候,适当地使用条件表达式也是很好的选择。
2.10.3 Python解释器
最后简单总结一下Python解释器的工作方式。
Python系统(解释器)处理程序时,基本方式是按行读入和处理:
- 默认方式是按行处理,遇到换行时就认为语句(或表达式)结束,就会去执行这个语句(或求值表达式)。因此程序不能随意地在语句(或表达式)中间换行。
- 如果在读入一行的最后遇到反斜线符号 ,解释器就丢掉反斜线符及随后的换行符,把下一行的内容看作是本行内容的继续(续行)。
- 如果被读入行中存在尚未配对的括号,同样认为下一行是本行的继续。
- 以换行结尾的一系列字符构成一个物理(的程序)行,解释器将根据上面规则把连续几个物理行拼接成一个逻辑的程序行(逻辑行),一次处理一个逻辑行。
- 如果读到的行是一个复杂结构的头部,解释器就会继续读完这个结构(根据代码的退格形式),而后一次完成这个结构的处理。
- 在交互式的工作方式下,Python解释器的基本处理循环中顺序做三件事:
- 读入一个逻辑的程序行,或者一个跨越几行的复杂结构,如def、if、for、while等复杂结构;
- 处理读入的结构(完成它要求的操作);
- 输出计算结果(如果有非None结果),或者报错。
- 处理模块中的代码时,解释器也采用同样处理规则,只是不显示求值结果。