列表解析:
什么是列表解析/推导(list comprehension):
Python列表解析是一种Python的语法,使用这种语法,可以遍历列表中的元素并进行特定的操作“和/或”过滤,并生成一个新的列表。
列表解析的作用:
列表解析可以将原本需要多行编写的代码简化为一行,并且可以带来很高的可读性和逼格,某些时候还可以让你少起一个变量名(这一点也很有用),最重要的是可以带来更高的效率(因为它再循环时调用了一些更底层的函数)
什么时候要用列表解析:
当需要对某个可迭代对象中的元素,进行某些遍历的操作、过滤时,便可以采用列表解析。
列表解析的定义:
[expr for iter_var initerable] 和 [expr foriter_var in iterable if cond_expr],其中第一种在遍历列表时是不包含过滤操作的,第二种包含一个过滤条件。 expr 是一个表达式(可以是一个方法、函数、lamda表达式等),iterable 是一个可迭代的对象(一般是一个列表或元祖),iter_var 是 iterable 中的一个元素,cond_expr是一个条件表达式。
列表解析也可以理解为一个函数,结构如下:
def func(iterable):
m_list = []
for iter_var in iterable:
m_list.append(exper(iter_var))
return m_list
有过滤条件的:
def func(iterable):
m_list = []
for iter_var in iterable:
if cond_expr:
m_list.append(exper(iter_var))
return m_list
列表解析的操作必须是一个表达式:
列表解析 [expr for iter_var initerable] 中的 expr 必须是一个表达式(如 lamda, function, 类中的方法) 例如: # 将 string_list_list 中的 ["hello"] 都换成 ["bye"]
string_list_list = [["hello"], ["bye"], ["hello"], ["bye"]] [string_list[0] = "bye" for string_list in string_list_list if string_list[0] == "hello"] 相当于: for string_list in string_list_list: if string_list[0] == "hello": string_list[0] = "bye" 但是 前者的列表解析是错误的,因为 赋值操作 string_list[0] = "bye" 并不是一个表达式,而是一个语句。而列表解中的 expr 析必须是一个表达式 如果想用列表解析完成此例子中的赋值操作,可以使用具体的等价表达式来进行:
[string_list.__setitem__(0, "bye") for string_list in string_list_list if string_list[0] == "hello"] 表达式,语句又很么区别呢,简单的来说,表达如 2*3,调用函数,调用方法等,表达式一定有一个值(所以在交互式的python解释器中,输入一个表达式执行后必然有一个结果)。 语句是一段可执行的代码。如if 语句,赋值语句 for语句等。语句本身并没有一个值(以在交互式的python解释器中,输入一个语句后并不会有立即的结果)
通俗的来讲列表解析:
即将可迭代(iterable)对象中的每一个元素(iter_var),经过expr处理后的内容,加入到新的列表中,如果有过滤条件(cond_expr),则将满足过滤条件的内容加入到新的列表,最后将新的列表返回。
列表解析的地位:
Python 中还有与列表解析相近功能的内建函数,如: map() # 对可迭代对象中的元素进行某些操作 reduce() # 叠加可迭代对象中的元素 filter() # 过滤可迭代对象中的元素 列表解析加入Python的时间要晚于这三个内建函数,并且列表解析在功能上基本可以取代这三个函数,所以如果你还不了解这三个函数的用法,学会列表解析后基本上也不需要能使用它们了。
在列表解析之后,又有生成器表达式、字典解析/推导、集合解析/推导加入到Python中来,但他们的使用方法鱼列表解析也非常相近,本文后面也会讲到。
列表解析的实际用例:
例1:
数据:
int_list = [1, 45, 54, 23, 6, 123, 32, 2]
将列表中的每个元素加1:
int_list = [x + 1 for x in int_list]
相当于传统写法:
for x in int_list:
m_int_list.append(x + 1)
int_list = m_int_list
得到输出:
for x in int_list:
m_int_list.append(x + 1)
int_list = m_int_list
如果只想将奇数加1呢:
加一个过滤条件即可:
int_list = [x + 1 for x in int_list if x % 2]
也可以写成:
def func(x):
return x + 1
int_list = [func(x) for x in int_list if x % 2]
相当于传统写法:
for x in int_list:
if x % 2:
m_int_list.append(x + 1)
int_list = m_int_list
得到输出:
print(int_list )
[2, 46, 24, 124]
例2:
某文本内容如下:
/root/test
acute exactly fabric
sustain
disarm assemble
cabin cheek
crust league minor
misunderstand shy
succeed vacation asleep bitterly custom
读取文件并去除每一行末尾的换行符:
with open("/root/test") as fd:
contest = [line.rstrip("\n") for line in fd.readlines()]
相当于传统写法:
with open("/root/test") as fd:
contest = []
for line in fd.readlines():
contest.append(line.rstrip("\n"))
得到输出(注意空行还未被去除):
print(contest)
['acute exactly fabric', 'sustain', 'disarm assemble', 'cabin cheek', '', 'crust league minor',
'', 'misunderstand shy','', 'succeed vacation asleep bitterly custom']
进一步的,如果想得到一行内容超过10个字符的行呢:
加一个过滤条件即可
with open("/root/test") as fd:
than10_contest = [line.rstrip("\n") for line in fd.readlines() if len(line) > 10]
相当于传统写法:
with open("/root/test") as fd:
than10_contest = []
for line in fd.readlines():
if len(line) > 10:
than10_contest.append(line.rstrip("\n"))
得到输出:
print(than10_contest)
['acute exactly fabric', 'disarm assemble', 'cabin cheek', 'crust league minor',
'misunderstand shy', 'succeed vacation asleep bitterly custom']
再进一步的,如果想将每个单词的首字母都大写呢:
再嵌套一层for循环即可
with open("/root/test") as fd:
up_than10_contest = [words.capitalize() for line in fd.readlines() if len(line) > 10
for words in line.rstrip("\n").split(" ")]
相当于传统写法:
with open("/root/test") as fd:
up_than10_contest = []
for line in fd.readlines():
if len(line) > 10:
for words in line.rstrip("\n").split(" "):
up_than10_contest.append(words.capitalize())
得到输出:
print(up_than10_contest)
['Acute', 'Exactly', 'Fabric', 'Disarm', 'Assemble', 'Cabin', 'Cheek', 'Crust', 'League', 'Minor', 'Misunderstand',
'Shy', 'Succeed', 'Vacation', 'Asleep', 'Bitterly', 'Custom']
生成器表达式:
pass
字典推导:
pass
集合推导:
pass