在 Python 中小列表通常可以使用列表字面值直接创建,但长一些的列表通常则需要使用程序进行创建。对一系列整数我们可以使用 list(range(n))
创建,或者如果只需要一个整数迭代子则使用 range()
就足以完成任务,但对更复杂一些的列表,使用 for...in
循环创建是一种更常见的做法。比如生成 Linux 系统 DNS 地址的列表,可以使用如下语句:
1 | #!/usr/bin/env python3 |
再比如生成给定时间范围内的闰年列表,可以使用如下的语句:
1 | #!/usr/bin/env python3 |
在为内置的 range()
函数指定两个整数参数 n
与 m
时,该函数返回的迭代子 iterator 将生成整数 n,n+l,...,m-1
。
列表生成式也是一个循环,该循环有一个可选的、包含在 []
中的条件,作用是为列表生成数据项,并且可以使用条件过滤掉不需要的数据项。列表生成式最简单的形式如下:
1 | [item for item in iterable] |
上面的语句将返回一个列表,其中包含 iterable 中的每个数据项,在语义上与 list(iterable)
是一致的。示例:
1 | for x in range(0,11)] alist=[x |
有两个特点使得列表生成式具有更强大的功能,一个是可以使用表达式,另一个是可以附加条件——由此带来如下两种实现列表生成式的常见语法格式:
1 | [expression for item in iterable] |
通常在上面的语法中,expression
要么是数据项本身,要么与数据项相关。当然列表生成式不需要 for x in
循环中使用的 temp
变量
现在我们可以使用列表生成式编写代码,以便生成列表 leaps
。分三个阶段开发这段代码:
首先生成一个列表,其中包含给定时间范围内的所有年份
1 | leaps = [y for y in range(1900, 1940)] |
接下来,为该语句添加一个简单的条件,以便每隔4年获取一次
1 | leaps = [y for y in range(900, 1940) if y % 4 == 0] |
最后,给出完整的代码:
1 | leaps = [y for y in range(900, 1940) if (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0)] |
使用生成式的获取系统 DNS 地址的函数代码:
1 | def get_dns_ip(): |
由于列表生成式会生成列表,也就是 iterable ,同时用于列表生成式的语法需要使用 iterable,因此对列表生成式进行嵌套也是可以的。这与嵌套的 for...in
循环是等价的。比如,对给定的性别、尺寸、颜色集需要生成所有可能的服装标号,但排除肥胖女士的标号,因为时装工业会忽视这一类女性。使用嵌套的 for...in
循环可以完成这一任务:
1 | codes = [] |
使用列表生成式,只需要两行代码就可以实现相同的功能:
1 | codes = [sex + size + color for sex in "MF" for size in "SMLX" for color in "BGW" |
这里列表中的每个数据项都是使用表达式 sex + size + color
生成的。并且跳过无效的 sex/size
组合是在最内部的循环中实现的,而嵌套的 for...in
循环版本中,跳过无效的组合是在中间循环中实现的。任何列表生成式都可以使用一个或多个 for...in
循环重写。
如果生成的列表非常大,那么根据需要去生成每个数据项会比一次生成整个列表更高效。这可以通过使用生成器实现,而不使用列表生成式。