当前位置: 首页 > 图灵资讯 > 行业资讯> 深入理解Python中的生成器

深入理解Python中的生成器

发布时间:2025-03-04 22:16:03

我们可以通过列表生成直接创建列表。然而,由于内存的限制,列表容量必须有限。此外,创建一个包含100万元素的列表

手表不仅占用了很大的存储空间,而且如果我们只需要访问前几个元素,那么后面绝大多数元素占用的空间就被浪费了。

因此,如果列表元素可以按照某种算法计算,我们能在循环过程中不断计算后续元素吗?这样,就没有必要创建一个完整的列表,以节省大量的空间。在Python中,这种循环计算机制被称为生成器(Generator)。

创建generator的方法有很多。第一种方法很简单。只要将列表生成式[]改为(),就会创建generator:

>>>L=[x*xforxinrange(10)]>>>L
[0,1,4,9,16,25,36,49,64>>>
g=(x*xforxinrange(10))>>>g
<generatorobject<genexpr>at0x104feab4>

L和g的区别只在于最外层的[]和(),L是list,g是generator。

我们可以直接打印list的每一个元素,但是如何打印generator的每一个元素呢?

若要逐一打印,可通过generatornext()方法:

>>>g.next()
0
>>>g.next()
1
>>>g.next()
4
>>>g.next()
9
>>>g.next()
16
>>>g.next()
25
>>>g.next()
36
>>>g.next()
49
>>>g.next()
64
>>>g.next()
81
>>>g.next()
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
StopIteration

正如我们所说,generator保存算法。每次调用next(),计算下一个元素的值,直到计算到最后一个元素,没有更多的元素,抛出stopiteration的错误。

当然,以上不断调用next()的方法太不正常了。正确的方法是使用for循环,因为generator也是可迭代的对象:

>>>g=(x*xforxinrange(10))
>>>forning:
...printn
...
0
1
4
9
16
25
36
49
64
81

因此,在我们创建了一个generator之后,我们基本上永远不会调用next()方法,而是通过for循环迭代它。

generator非常强大。假如算法比较复杂,用类似列表生成的for循环无法实现,也可以用函数来实现。

例如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任何一个数都可以从前两个数加起来:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列不能用列表生成式写出来,但很容易用函数打印出来:

deffib(max):
n,a,b=0,0,1
whilen<max:printb
a,b=b,a+b
n=n+1

以上函数可输出斐波那契数列的前N个数:

>>>fib(6)
1
1
2
3
5
8

仔细观察,我们可以看到fib函数实际上定义了斐波拉契数列的计算规则,可以从第一个元素开始计算后续任何元素。这种逻辑实际上与generator非常相似。

也就是说,上面的函数离generator只有一步之遥。要把fib函数变成generator,只需要print b改为yield b就可以了:

deffib(max):
n,a,b=0,0,1
whilen<max:
yieldb
a,b=b,a+b
n=n+1

这是定义generator的另一种方法。如果一个函数定义包含yield关键字,那么这个函数不再是一个普通的函数,而是一个generator:

>>>fib(6)
<generatorobjectfibat0x104feaaa>

在这里,最难理解的是generator和函数的执行过程是不同的。函数是按顺序执行的,遇到return语句或最后一行函数语句时返回。成为generator的函数在每次调用next()时执行,遇到yield语句返回时继续从上次返回的yield语句执行。

举个简单的例子,定义一个generator,依次返回数字1、3、5:

>>>defodd():
...print'step1'
...yield1
...print'step2'
...yield3
...print'step3'
...yield5
...
>>>o=odd()
>>>o.next()
step1
1
>>>o.next()
step2
3
>>>o.next()
step3
5
>>>o.next()
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
StopIteration

可以看出,odd不是普通函数,而是generator。在执行过程中,yield被中断,下次将继续执行。执行三次yield后,没有yield可以执行,因此第四次调用next()报告错误。

回到fib的例子中,如果我们在循环过程中不断调用yield,我们将继续中断。当然,我们应该为退出循环设置一个条件,否则会列出一个数字。

同样,在将函数改为generator后,我们基本上从不使用next()来调用它,而是直接使用for循环来迭代:

>>>forninfib(6):
...printn
...
1
1
2
3
5
8

小结

generator是一种非常强大的工具,在Python中,可以简单地将列表生成式改为generator,也可以通过函数实现复杂逻辑的generator。

要了解generator的工作原理,它是在for循环过程中不断计算下一个元素,并在适当的条件下结束for循环。对于函数改成的generator,遇到return语句或执行到函数体的最后一行语句是结束generator的指令,for循环结束。

相关文章

python3兼容python2吗

python3兼容python2吗

2025-05-09
python3 whl怎么安装

python3 whl怎么安装

2025-05-09
python 字典怎么提取value

python 字典怎么提取value

2025-05-09
python 怎样计算字符串的长度

python 怎样计算字符串的长度

2025-05-09
python 怎么样反向输出字符串

python 怎么样反向输出字符串

2025-05-09
python 怎么判断字符串开头

python 怎么判断字符串开头

2025-05-09