生成器(generator)
生成器:是一种特殊的迭代器,生成器自动实现了“迭代器协议”(即iter和next方法),不需要再手动实现两方法。分为生成器函数和生成器表达式两种。
第一类:生成器函数
使用 def 定义函数,但是,使用yield而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 菲波那切数列
def Fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return '亲!没有数据了...'
# 调用方法,生成出10个数来
f=Fib(10)
# 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
while True:
try:
x=next(f)
print("f:",x)
except StopIteration as e:
print("生成器最后的返回值是:",e.value)
break
|
执行以上程序会输出如下结果:
1
2
3
4
5
6
7
8
9
10
11
|
f: 1
f: 1
f: 2
f: 3
f: 5
f: 8
f: 13
f: 21
f: 34
f: 55
生成器最后的返回值是: 亲!没有数据了...
|
第二类:生成器表达式
生成器表达式是用一对小括号()括起来的表达式。按需产生一个生成器结果对象,要想拿到每一个元素,就需要循环遍历。
例如:
1
2
3
4
5
6
7
|
# 列表l
l = [1,2,3,4,5]
# 生成器generator,类似于list,但是是把[]改为()
gen=(a for a in l)
print(type(gen))
for i in gen:
print(i)
|
执行以上程序会输出如下结果:
1
2
3
4
5
6
|
<class 'generator'>
1
2
3
4
5
|
如果生成器表达式是一个函数调用过程中的唯一参数,可以省略括号。
例如:
1
2
3
|
l = [1,2,3,4,5]
t1 = tuple(item for item in l) # (1, 2, 3, 4, 5)
t2 = tuple((item for item in l)) # 生成器表达式的括号可以省略(1, 2, 3, 4, 5)
|
为什么要使用生成器?
因为效率。使用生成器表达式可以同时节省cpu和内存。如果你构造一个列表(list)的目的仅仅是传递给别的函数,比如传递给tuple()或者set(), 那就用生成器表达式替代吧!
例如:
1
2
3
4
5
|
# 本案例是直接把列表转化为元组
# 列表l
l = [1,2,3,4,5]
kk=tuple((a for a in l)) # 也可以简写kk=tuple(a for a in l)
print(kk) # 结果是:(1, 2, 3, 4, 5)
|
python内置一些函数,可识别生成器表达式。
sum函数是计算序列的总和。sum(1,2,3)
结果是6。
result=sum((a for a in range(3)))
中的
(a for a in range(3))
是生成器表达式。也可以简写
result=sum(a for a in range(3))
下面是列表推导式,不是生成器
result2=sum([a for a in range(3)])
生成器表达式与列表推导(列表生成式)区别
列表推导是用[]括起来的表达式列表。类型是list。
例如:
1
2
3
|
l = [x * x for x in range(1, 11)]
print(type(l))
print(l)
|
执行以上程序会输出如下结果:
1
2
|
<class 'list'>
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
生成器表达式是用()括起来。类型是generator。
例如:
1
2
3
|
g = (x * x for x in range(1, 11))
print(type(g))
print(g)
|
执行以上程序会输出如下结果:
1
2
|
<class 'generator'>
<generator object <genexpr> at 0x7f06351ed4c0>
|
生成器表达式和列表推导都可以for循环后面还可以加上if判断。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
l = [x * x for x in range(1, 11) if x % 2 == 0]
g = (x * x for x in range(1, 11) if x % 2 == 0)
print(l) # [4, 16, 36, 64, 100]
print(g) # <generator object <genexpr> at 0x7f10b8e464c0>。g是一个generator。通过next()函数获得下一个返回值。
print(next(g)) # 4
print(next(g)) # 16
print(next(g)) # 36
print(next(g)) # 64
print(next(g)) # 100
print(next(g)) # 已经到达生成器的末尾,抛出StopIteration异常。
Traceback (most recent call last):
File "main.py", line 10, in <module>
print(next(g)) # 100
StopIteration
|
还可以使用两层循环,可以生成全排列:
1
2
3
4
|
l = [m + n for m in 'ABC' for n in 'XYZ']
g = (m + n for m in 'ABC' for n in 'XYZ')
print(l) #['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
print(g) #<generator object <genexpr> at 0x7f00f6abe4c0>
|
转载请注明本网址。