条件、循环及其他语句
你现在肯定有点不耐烦了。这些数据类型确实好,可你却没法使用它们来做什么,不是吗?
下面加快点速度。你已见过几种语句(print语句、import语句和赋值语句),先来看看这些
语句的其他一些用法,再深入探讨条件语句和循环语句。然后,我们将介绍列表推导,它们虽然
是表达式,但工作原理几乎与条件语句和循环语句相同。最后,我们将介绍pass、del和exec。
5.1 再谈 print 和 import
随着你对Python的认识越来越深入,可能发现有些你自以为很熟悉的方面隐藏着让人惊喜的
特性。下面就来看看print和import隐藏的几个特性。虽然print现在实际上是一个函数,但以前
却是一种语句,因此在这里进行讨论。
对很多应用程序来说,使用模块logging来写入日志比使用print更合适,详情请参阅第19章。
5.1.1 打印多个参数
你知道,print可用于打印一个表达式,这个表达式要么是字符串,要么将自动转换为字符
串。但实际上,你可同时打印多个表达式,条件是用逗号分隔它们:
>>> print('Age:', 42)
Age: 42
如你所见,在参数之间插入了一个空格字符。在你要合并文本和变量值,而又不想使用字符
串格式设置功能时,这种行为很有帮助。
>>> name = 'Gumby'
>>> salutation = 'Mr.'
>>> greeting = 'Hello,'
>>> print(greeting, salutation, name)
Hello, Mr. Gumby
如果字符串变量greeting不包含逗号,如何在结果中添加呢?你不能像下面这样做:
print(greeting, ',', salutation, name)
因为这将在逗号前添加一个空格。下面是一种可行的解决方案:
print(greeting + ',', salutation, name)
它将逗号和变量greeting相加。如果需要,可自定义分隔符:
>>> print("I", "wish", "to", "register", "a", "complaint", sep="_")
I_wish_to_register_a_complaint
你还可自定义结束字符串,以替换默认的换行符。例如,如果将结束字符串指定为空字符串,
以后就可继续打印到当前行。'
print('Hello,', end='')
print('world!')
上述代码打印Hello, world!①。
① 仅当这些代码包含在脚本中时才如此。在交互式Python会话中,将分别执行每条语句并打印其内容。
5.1.2 导入时重命名
从模块导入时,通常使用
import somemodule
或使用
from somemodule import somefunction
或
from somemodule import somefunction, anotherfunction, yetanotherfunction
或
from somemodule import *
仅当你确定要导入模块中的一切时,采用使用最后一种方式。但如果有两个模块,它们都包
含函数open,该如何办呢?你可使用第一种方式导入这两个模块,并像下面这样调用函数:
module1.open(...)
module2.open(...)
但还有一种办法:在语句末尾添加as子句并指定别名。下面是一个导入整个模块并给它指定
别名的例子:
>>> import math as foobar
>>> foobar.sqrt(4)
2.0
下面是一个导入特定函数并给它指定别名的例子:
>>> from math import sqrt as foobar
>>> foobar(4)
2.0
对于前面的函数open,可像下面这样导入它们:
from module1 import open as open1
from module2 import open as open2
有些模块(如os.path)组成了层次结构(一个模块位于另一个模块中)。有关模块结构
的详细信息,请参阅10.1.4节。
5.2 赋值魔法
即便是不起眼的赋值语句也蕴藏着一些使用窍门。
5.2.1 序列解包
赋值语句你见过很多,有的给变量赋值,还有的给数据结构的一部分(如列表中的元素和切
片,或者字典项)赋值,但还有其他类型的赋值语句。例如,可同时(并行)给多个变量赋值:
>>> x, y, z = 1, 2, 3
>>> print(x, y, z)
1 2 3
看似用处不大?看好了,使用这种方式还可交换多个变量的值。
>>> x, y = y, x
>>> print(x, y, z)
2 1 3
实际上,这里执行的操作称为序列解包(或可迭代对象解包):将一个序列(或任何可迭代
对象)解包,并将得到的值存储到一系列变量中。下面用例子进行解释。
>>> values = 1, 2, 3
>>> values
(1, 2, 3)
>>> x, y, z = values
>>> x
1
这在使用返回元组(或其他序列或可迭代对象)的函数或方法时很有用。假设要从字典中随
便获取(或删除)一个键值对,可使用方法popitem,它随便获取一个键值对并以元组的方式
返回。接下来,可直接将返回的元组解包到两个变量中。
>>> scoundrel = {'name': 'Robin', 'girlfriend': 'Marion'}
>>> key, value = scoundrel.popitem()
>>> key
'girlfriend'
>>> value
'Marion'
这让函数能够返回被打包成元组的多个值,然后通过一条赋值语句轻松地访问这些值。要解
包的序列包含的元素个数必须与你在等号左边列出的目标个数相同,否则Python将引发异常。
>>> x, y, z = 1, 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack
>>> x, y, z = 1, 2, 3, 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
可使用星号运算符(*)来收集多余的值,这样无需确保值和变量的个数相同,如下例所示:
>>> a, b, *rest = [1, 2, 3, 4]
>>> rest
[3, 4]
还可将带星号的变量放在其他位置。
>>> name = "Albus Percival Wulfric Brian Dumbledore"
>>> first, *middle, last = name.split()
>>> middle
['Percival', 'Wulfric', 'Brian']
赋值语句的右边可以是任何类型的序列,但带星号的变量最终包含的总是一个列表。在变量
和值的个数相同时亦如此。
>>> a, *b, c = "abc"
>>> a, b, c
('a', ['b'], 'c')
这种收集方式也可用于函数参数列表中(参见第6章)。
5.2.2 链式赋值
链式赋值是一种快捷方式,用于将多个变量关联到同一个值。这有点像前一节介绍的并行赋
值,但只涉及一个值:
x = y = somefunction()
上述代码与下面的代码等价:
y = somefunction()
x = y
请注意,这两条语句可能与下面的语句不等价:
x = somefunction()
y = somefunction()
有关这方面的详细信息,请参阅5.4.6节介绍相同运算符(is)的部分。
5.2.3 增强赋值
可以不编写代码x = x + 1,而将右边表达式中的运算符(这里是+)移到赋值运算符(=)
的前面,从而写成x += 1。这称为增强赋值,适用于所有标准运算符,如*、/、%等。
>>> x = 2
>>> x += 1
>>> x *= 2
>>> x
6
增强赋值也可用于其他数据类型(只要使用的双目运算符可用于这些数据类型)。
>>> fnord = 'foo'
>>> fnord += 'bar'
>>> fnord *= 2
>>> fnord
'foobarfoobar'
通过使用增强赋值,可让代码更紧凑、更简洁,同时在很多情况下的可读性更强。