生成器(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>

转载请注明本网址。