words=['Are','abc','pass','busi','fruit','quit']
size=len(words)
newlist=[]
for i in range(size):
if words[i].strip().istitle():
newlist.append(words[i])
print(newlist)
['Are']
那么,这段程序有什么问题吗?就程序本身来说并没有什么明显的问题,但有更好的实现方式。 这就是列表解析(list comprehension)所涉及的内容了。
先来了解一下列表解析的基本知识点。
列表解析的语法为: [expr for iter_item in iterable if cond_expr]
。
它迭代 iterable
中的每一个元素,当条件满足的时候便根据表达式 expr
计算的内容生成一个元素并放入新的列表中,
依次类推,并最终返冋整个列表。在语法上,它等价于下面代码段:
Newlist =[]
iterable=[]
for iter_item in iterable:
if cond_expr:
Newlist.append(expr)
其中条件表达式不是必需的,如果没有条件表达式,
就直接将 expr
中计算出的元素加入 List
中,列表解析的使用非常灵活。
1)支持多重嵌套。如果需要生成一个二维列表可以使用列表解析嵌套的方式。示例如下:
nested_list=[['Hello ','world'],['goodbye','world']]
nested_list=[[s.upper() for s in xs] for xs in nested_list]
print(nested_list)
[['HELLO ', 'WORLD'], ['GOODBYE', 'WORLD']]
2)支持多重迭代。
下面的例子中 a
, b
分别对应两个列表中的元素,[(a,b) for a in [' a' , ' 1', 1 , 2] for b in ['l',3,4,'b' ] if a != b]
表示,
列表 (' a', 'l')
和 (' a', 3)
依次求笛卡儿积之后并去掉元素值相等的元组之后所剩下的元组的集合。
[(a,b) for a in [' a' , ' 1', 1 , 2] for b in ['l',3,4,'b' ] if a != b]
[(' a', 'l'), (' a', 3), (' a', 4), (' a', 'b'), (' 1', 'l'), (' 1', 3), (' 1', 4), (' 1', 'b'), (1, 'l'), (1, 3), (1, 4), (1, 'b'), (2, 'l'), (2, 3), (2, 4), (2, 'b')]
3)列表解析语法中的表达式可以是简单表达式,也可以是复杂表达式,甚至是函数。
def f(v):
if v%2==0:
v=v**2
else:
v=v+1
return v
[f(v) for v in [2,3,4,-1] if v>0]
[4, 4, 16]
[v**2 if v%2==0 else v+1 for v in [2,3,4,-1] if v>0]
[4, 4, 16]
4)列表解析语法中的 iterable
可以是任意可迭代对象。
下面的例子中把文件句柄当做一个可迭代对象,可轻易读出文件内容。
fh=open("/etc/os-release","r")
res=[i for i in fh if "Ubuntu" in i]
print(res)
['PRETTY_NAME="Ubuntu 24.04.2 LTS"\n', 'NAME="Ubuntu"\n']
使用列表表达式生成列表
1)使用列表解析更为直观清晰,代码更为简洁。本节开头的例子改用列表解析,直接可将代码行数减少为2行, 这在大型复杂应用程序中尤为重要,因为这意味着潜在的缺陷较小, 同时代码清晰直观,更容易阅读和理解,可维护性更强。
2)列表解析的效率更高。本节开头的例子用两种不同方法实现后进行测试,测试结果表明列表解析在时间上有一定的优势,
这主要是因为普通循环生成 List
的时候一般需要多次调用 append()
函数,增加了额外的时间开销。
需要说明的是对于大数据处理,列表解析并不是一个最佳选择,过多的内存消耗可能会导致 MemoryError
。
3)除了列表可以使用列表解析的语法之外,其他几种内建的数据结构也支持,
比如元组 (tuple)的初始化语法是 (expr for iter_item in iterable if cond_expr)
,
而集合(set)的初始化语法是 {expr for iter_item in iterable if cond_expr}
,
甚至字典(diet)也有类似的语法 {exprl, expr2 for iterjtem in iterable if cond;xpr}
,它们的使用类似列表解析,
但需要注意,因为元组也适用赋值语句的装筘和拆箱机制,
所以需要注意(1)与(U是不同的:前者为数字1,后者才代表元组(注意1后面的)
type((1))
int
type((1,))
tuple
此外,当函数接受一个可迭代对象参数时,可以使用元组的简写方式。
def foo(a):
for i in a:
print(i)
foo([1,2,3])
1 2 3
foo(i for i in range(3) if i%2==0 )
0 2