生成器表达式、集合解析式、字典解析式

生成器表达式

生成器的语法为:(返回值 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]



posted on 2019-10-14 21:24  xpc199151  阅读(505)  评论(0编辑  收藏  举报

导航