Python3: 生成器Generators详解

三个部分

可迭代对象(Iterable)

Python中任意的对象,只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法,那么它就是一个可迭代对象。

迭代器(Iterator)

任意对象,只要定义了next(Python2)或者__next__方法,它就是一个迭代器。

迭代(Iteration)

简单来说,它就是从某个地方(比如列表)取出一个元素的过程。当使用一个循环来遍历某个东西时,这个过程本身就叫迭代。

生成器也是一种迭代器,但是只能对其迭代一次。这是因为他们并没有把所有的值存在内存中,而是在运行时生成值。通过遍历来使用他们,要么用一个“for”循环,要么将它们传递给任意可以进行迭代的函数和结构。大多数时候生成器是以函数来实现的。然而,它们并不返回一个值,而是yield一个值。

# 简单的例子
def generator_function():
    for i in range(10):
        yield i
for item in generator_function():
    print(item)
0
1
2
3
4
5
6
7
8
9

但生成器最佳的应用场景是:你不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环。(这样会消耗大量资源)

许多Python2里的标准函数都会返回列表,而Python3都修改成了返回生成器,因为生成器占用更少的资源。

# 计算斐波那契数列的生成器
# 用这种方式,可以不用担心它会使用大量资源
def fibon(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b
for x in fibon(100):
    print(x)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
2971215073
4807526976
7778742049
12586269025
20365011074
32951280099
53316291173
86267571272
139583862445
225851433717
365435296162
591286729879
956722026041
1548008755920
2504730781961
4052739537881
6557470319842
10610209857723
17167680177565
27777890035288
44945570212853
72723460248141
117669030460994
190392490709135
308061521170129
498454011879264
806515533049393
1304969544928657
2111485077978050
3416454622906707
5527939700884757
8944394323791464
14472334024676221
23416728348467685
37889062373143906
61305790721611591
99194853094755497
160500643816367088
259695496911122585
420196140727489673
679891637638612258
1100087778366101931
1779979416004714189
2880067194370816120
4660046610375530309
7540113804746346429
12200160415121876738
19740274219868223167
31940434634990099905
51680708854858323072
83621143489848422977
135301852344706746049
218922995834555169026
354224848179261915075
# 不用生成器,计算很大时,可能会用尽所有的资源
def fibon(n):
    a = b = 1
    result =[]
    for i in range(n):
        result.append(a)
        a, b = b, a+b
    return result
f = fibon(100)
print(f)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]

在测试生成器使用一次迭代之前,先了解一下Python内置函数:next()

它允许获取一个序列的下一个元素。

def generator_function():
    for i in range(3):
        yield i

gen = generator_function()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
0
1
2



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-5-fc13b4ccc394> in <module>()
      7 print(next(gen))
      8 print(next(gen))
----> 9 print(next(gen))


StopIteration: 

在yield掉所有的值后,next()触发一个StopIteration的异常。因为所有的值都被yield完了。

但为什么使用for循环时没有这个异常呢?

答案是:for循环会自动捕捉到这个异常并停止调用next()

# Python 中一些内置数据类型也支持迭代
my_String = "Python"
next(my_String)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-6-587e901c8cc9> in <module>()
      1 # Python 中一些内置数据类型也支持迭代
      2 my_String = "Python"
----> 3 next(my_String)


TypeError: 'str' object is not an iterator

很明显,str不是一个迭代器

# iter支持迭代的,它将根据一个可迭代对象返回一个迭代器对象
my_String = "Python"
my_Iter = iter(my_String)
next(my_Iter)
'P'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZPILOTE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值