生成器表达式、集合解析式、字典解析式
生成器表达式
生成器的语法为:(返回值 for 元素 in 可迭代对象 if 条件) ,它就是将列表解析式的中括号换成小括号就行了 。它返回的是一个可迭代的生成器对象。
(x for x in range(1,5)) 结果为: <generator object <genexpr> at 0x03F3F1B0>
生成器和列表解析式的区别
生成器表达式是按需计算(或称惰性求值、延迟计算),需要的时候才计算值,而列表解析式是立即返回值。
生成器是一个迭代器,也是可迭代对象。
#延迟计算,返回迭代器,可以迭代, 从前到后走完一遍后,不能回头 g = ("{:04}".format(i) for i in range(1,11)) print(next(g)) for x in g: print(x) print('~~~~~~~~~~~~') for x in g: print(x) 结果为: 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 ~~~~~~~~~~~~ #立即计算,返回的不是迭代器,返回可迭代对象列表,从前到后走完一遍后,可以重新回头迭代 g = ["{:04}".format(i) for i in range(1,11)] for x in g: print(x) print('~~~~~~~~~~~~') for x in g: print(x) 结果为: 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 ~~~~~~~~~~~~ 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010
比如it = (print("{}".format(i+1)) for i in range(2))
first = next(it)
second = next(it)
val = first + second
val的值是什么? 答案是不能相加
val = first + second 语句之后能否再次next(it)? 不能再next
it = (print("{}".format(i+1)) for i in range(2))#IT是生成器 first = next(it) second = next(it) val = first + second 结果为: 1 2 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-175-9bc925c5dd92> in <module> 2 first = next(it) 3 second = next(it) ----> 4 val = first + second TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType' next(it) 结果为: --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-176-bc1ab118995a> in <module> ----> 1 next(it) StopIteration:
it = (x for x in range(10) if x % 2)
first = next(it)
second = next(it)
val = first + second
val的值是什么?4
val = first + second 语句之后能否再次next(it)? 能
it = (x for x in range(10) if x % 2) first = next(it) print(first) second = next(it) print(second) val = first + second print(val) an = next(it) print(an) 结果为: 1 3 4 5
生成器表达式和列表解析式对比
计算方式:生成器表达式延迟计算,列表解析式立即计算
内存占用:单从返回值本身来说,生成器表达式省内存,列表解析式返回新的列表。生成器没有数据,内存占用极少,但是使用的时候,虽然一个个返回数据,但是合起来占用的内存也差不多。列表解析式构造新的列表需要占用内存。
计算速度:单看计算时间看,生成器表达式耗时非常短,列表解析式耗时长,但是生成器本身并没有返回任何值,只返回了一个生成器对象,列表解析式构造并返回了一个新的列表 。
集合解析式
集合解析式的语法: {返回值 for 元素 in 可迭代对象 if 条件},列表解析式的中括号换成大括号{}就行了,它会立即返回一个集合。
{(x,x+1) for x in range(10)} 结果为: {(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10)} {[x] for x in range(10)} {[x] for x in range(10)} 结果为: --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-189-5bb81d40d8ae> in <module> ----> 1 {[x] for x in range(10)} <ipython-input-189-5bb81d40d8ae> in <setcomp>(.0) ----> 1 {[x] for x in range(10)} TypeError: unhashable type: 'list'
字典解析式
字典解析式的语法:{返回值 for 元素 in 可迭代对象 if 条件},列表解析式的中括号换成大括号{}就行了,使用key:value形式,它会立即返回一个字典。
{x:(x,x+1) for x in range(10)} 结果为: {0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5), 5: (5, 6), 6: (6, 7), 7: (7, 8), 8: (8, 9), 9: (9, 10)} {x:[x,x+1] for x in range(10)} 结果为: {0: [0, 1], 1: [1, 2], 2: [2, 3], 3: [3, 4], 4: [4, 5], 5: [5, 6], 6: [6, 7], 7: [7, 8], 8: [8, 9], 9: [9, 10]} {(x,):[x,x+1] for x in range(10)} 结果为: {(0,): [0, 1], (1,): [1, 2], (2,): [2, 3], (3,): [3, 4], (4,): [4, 5], (5,): [5, 6], (6,): [6, 7], (7,): [7, 8], (8,): [8, 9], (9,): [9, 10]} {[x]:[x,x+1] for x in range(10)} # --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-198-5f8fa7594e3f> in <module> ----> 1 {[x]:[x,x+1] for x in range(10)} # <ipython-input-198-5f8fa7594e3f> in <dictcomp>(.0) ----> 1 {[x]:[x,x+1] for x in range(10)} # TypeError: unhashable type: 'list' {chr(0x41+x):x**2 for x in range(10)}#16进制表示 结果为: {'A': 0, 'B': 1, 'C': 4, 'D': 9, 'E': 16, 'F': 25, 'G': 36, 'H': 49, 'I': 64, 'J': 81} {str(x):y for x in range(3) for y in range(4)} # 输出多少个元素? 结果为: {'0': 3, '1': 3, '2': 3}
ret = {}
for x in range(3):
for y in range(4):
ret[str(x)] = y#后面Y的值会覆盖前面的值
print(ret)
结果为:
{'0': 3, '1': 3, '2': 3}
总结
一般来说,应该多应用解析式,简短、高效 ,如果一个解析式非常复杂,难以读懂,要考虑拆解成for循环 ,同时应该注意生成器和迭代器是不同的对象,但都是可迭代对象。
练习题1:
比如有一个列表names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']],希望找出里面名字含有两个e的。
这个用列表推导就会很简单,而不用列表推导就会麻烦一点。
#不用列表推导式 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] a = [] for i in names: for j in i: if j.count("e")>=2: a.append(j) print(a) 结果为: ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
#用列表推导式 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] a = [j for i in names for j in i if j.count("e")>=2] print(a) 结果为: ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
下面这个题的输出结果是什么:
def add(a, b): return a + b def test(): for r_i in range(4): yield r_i g = test()#g是一个生成器对象 for n in [2, 10]: g = (add(n, i) for i in g) print(list(g)) 结果为什么是: [20, 21, 22, 23]