目录
列表推导是构建列表(list )的快捷方式,而生成器表达式则可以用
来创建其他任何类型的序列。如果你的代码里并不经常使用它们,那么
很可能你错过了许多写出可读性更好且更高效的代码的机会
2.2.1 列表推导和可读性
先来个小测试,你觉得示例
2-1
和示例
2-2
中的代码,哪个更容易读
懂?
示例 2-1 把一个字符串变成 Unicode 码位的列表
symbols = "$%^^&*"
codes = []
for symbol in symbols:
codes.append(ord(symbol))
print(codes)
示例 2-2 把字符串变成 Unicode 码位的另外一种写法
symbols = "$%^^&*"
codes = [ord(symbol) for symbol in symbols]
print(codes)
虽说任何学过一点 Python 的人应该都能看懂示例 2-1 ,但是我觉得如果学会了列表推导的话,示例 2-2 读起来更方便,因为这段代码的功能从字面上就能轻松地看出来。
for 循环可以胜任很多任务:遍历一个序列以求得总数或挑出某个特定的元素、用来计算总和或是平均数,还有其他任何你想做的事情。另一方面,列表推导也可能被滥用。通常的原则是,只用列表推导来创建新的列表 ,并且尽量 保持简短 。如果列表推导的代码 超过了两行 ,你可能就要考虑是不是得用 for 循环重写了 。这个度得你自己把握
Python 会 忽略 代码里 []、{} 和 () 中 的换行 ,因此如果你的代码里有多行的列表、列表推导、生成器表达式、字典这一类的,可以省略不太好看的续行符例如:for tshirt in ('{} {}'.format(c, s) for c in colors for s in sizes): print(tshirt)
python 2.x版本中 列表推导式中 for 之后的赋值操作 可能会影响列表推导式上下文同名变量例如: x = 'my precious'dummy = [x for x in 'ABC']print(x) # 输出:'c'如你所见, x 原本的值被取代了,但是这种情况在 Python 3 中是不会出现的列表推导、生成器表达式 ,以及同它们很相似的 集合(set)推导和 字典(dict)推导 , 在 Python 3 中都有了自己的局部作用域 ,就像函数似的。表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到 它们
2.2.2 列表推导同filter和map的比较
filter 和 map 合起来能做的事情,列表推导也可以做 而且不需要使用lambda 表达式,
注意 map/filter 组合起来用 不一定比列表推导快一些
beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
"""
filter(function, iterable)
function -- 判断函数。
iterable -- 可迭代对象
map(function, iterable, ...)
function -- 函数
iterable -- 一个或多个序列
"""
2.2.3 笛卡儿积
列表推导可以生成两个或以上的可迭代类型的笛卡儿积列表里的元素是由输入的可迭代类型的元素对构成的元组,因此笛卡儿积列表的长度等于输入变量的长度的乘积
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
tshirts = [(color, size)for color in colors for size in sizes]
print(tshirts)#[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'),('white', 'M'), ('white', 'L')]
"""
注意,这里两个循环的嵌套关系和上面列表推导中 for 从句的先后
顺序一样
等价于
for color in colors:
... for size in sizes:
... print((color, size))
"""
列表推导的作用只有一个: 生成列表 。如果想生成其他类型的序列,生成器表达式就派上了用场
2.2.4 生成器表达式
虽然也可以用 列表推导来初始化 元组、数组或其他序列类型,但是生成器表达式是更好的选择。这是因为 生成器表达式 背后 遵守了迭代器协议,可以逐个地产出元素 ,而 不是先建立一个完整的列表 ,然后再把这个列表传递到某个构造函数里。前面那种方式显然能够节省内存。生成器表达式的语法跟列表推导差不多,只不过把方括号换成圆括号而已。
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
res1=((c,s) for c in colors for s in sizes)
print("生成器 next方法{}".format(res1.__next__()))#<generator object <genexpr> at 0x01C40E30>
for i in res1:
print("for 循环 i={}".format(i))# 循环取出 res1的值
for i in res1:# 直接跳过本次循环 因为 生成器表达式 不能循环取值 (感觉和队列的形式很想)
print("for 循环 i={}".format(i))
""""
生成器 next方法('black', 'S')
for 循环 i=('black', 'M')
for 循环 i=('black', 'L')
for 循环 i=('white', 'S')
for 循环 i=('white', 'M')
for 循环 i=('white', 'L')
"""