Python教程-Python生成器
什么是Python生成器?
Python生成器是一种能够返回交叉对象并用于创建迭代器的能力。它同时遍历所有项目。生成器还可以是一个表达式,其语法类似于Python的列表推导。
在Python中创建迭代的复杂性很高;我们需要实现iter()和next()方法来跟踪内部状态。
创建迭代器是一个冗长的过程。这就是为什么生成器在简化这个过程中起着关键作用。如果在迭代中没有找到值,它会引发StopIteration异常。
如何在Python中创建生成器函数?
在Python中,创建生成器并不难。它类似于典型的能力,由def关键字标识,并且使用yield关键字而不是return。或者我们可以说,如果任何能力的主体包含yield语句,它会自动变成一个生成器能力。考虑以下示例:
def simple():
for i in range(10):
if(i%2==0):
yield i
#Successive Function call using for loop
for i in simple():
print(i)
输出:
0
2
4
6
8
yield与return的区别
yield语句负责控制生成器函数的流程。通过保存所有状态并向调用者产生yield,它终止函数的执行。稍后,当调用连续生成器时,它会恢复执行。在生成器函数中,我们可以使用多个yield语句。
return语句返回一个值并结束整个函数,函数中只能使用一个return语句。
使用多个yield语句
我们可以在生成器函数中使用多个yield语句。考虑以下示例:
def multiple_yield():
str1 = "First String"
yield str1
str2 = "Second string"
yield str2
str3 = "Third String"
yield str3
obj = multiple_yield()
print(next(obj))
print(next(obj))
print(next(obj))
输出:
First String
Second string
Third String
生成器函数与普通函数的区别
普通函数只包含一个return语句,而生成器函数可以包含一个或多个yield语句。
调用生成器函数时,普通函数会立即停止,并将控制权交给调用者。
局部变量的状态在调用之间保留。
函数终止时会自动引发StopIteration异常。
生成器表达式
我们可以轻松地创建生成器表达式,而无需使用用户定义的函数。它类似于lambda函数,可以创建一个匿名函数;生成器表达式创建了一个匿名生成器函数。
生成器表达式的表示方式类似于Python列表推导。唯一的区别是圆括号取代了方括号。生成器表达式一次只计算一个项目,而列表推导计算整个列表。
考虑以下示例:
list = [1,2,3,4,5,6,7]
# List Comprehension
z = [x**3 for x in list]
# Generator expression
a = (x**3 for x in list)
print(a)
print(z)
输出:
<generator object <genexpr> at 0x01BA3CD8>
[1, 8, 27, 64, 125, 216, 343]
在上面的程序中,列表推导返回了元素的立方列表,而生成器表达式返回了计算值的引用。我们可以不使用for循环,而是在生成器对象上调用next()。让我们考虑另一个示例:
list = [1,2,3,4,5,6]
z = (x**3 for x in list)
print(next(z))
print(next(z))
print(next(z))
print(next(z))
输出:
1
8
27
64
注意:当我们调用next()时,Python会在我们传递的函数上调用__next__()。
在上面的程序中,我们使用了next()函数,它返回了列表的下一个项目。
示例:编写一个程序,使用生成器打印给定数字的乘法表。
def table(n):
for i in range(1,11):
yield n*i
i = i+1
for i in table(15):
print(i)
输出:
15
30
45
60
75
90
105
120
135
150
在上面的示例中,生成器函数使用for循环进行迭代。
生成器的优点
生成器有许多优点。以下是其中几个:
1. 实现简单
与迭代器相比,生成器的实现更简单。在迭代器中,我们必须实现iter()和next()函数。
2. 内存高效
对于许多序列,生成器高效地利用内存。生成器函数计算值并挂起执行,而普通函数从列表中返回序列,首先在返回结果之前在内存中创建整个序列。它在连续调用时恢复。无限序列生成器是内存优化的一个很好的示例。让我们通过下面的示例使用sys.getsizeof()函数来说明。
import sys
# List comprehension
nums_squared_list = [i * 2 for i in range(1000)]
print(sys.getsizeof("Memory in Bytes:"nums_squared_list))
# Generator Expression
nums_squared_gc = (i ** 2 for i in range(1000))
print(sys.getsizeof("Memory in Bytes:", nums_squared_gc))
输出:
Memory in Bytes: 4508
Memory in Bytes: 56
从上面的输出可以看出,列表推导使用了4508字节的内存,而生成器表达式使用了56字节的内存。这意味着生成器对象比列表推导要高效得多。
3. 使用生成器进行流水线处理
使用生成器可以进行流水线处理,处理大型数据集或数据流,而无需使用额外的计算机内存。
假设我们有一个著名餐厅的日志文件。日志文件有一个部分(第四部分),用于记录每天卖出的汉堡数量,我们需要对其求和,以找出4年内总共卖出的汉堡数量。在这种情况下,生成器可以使用一系列操作创建一个流水线。其代码如下:
with open('sells.log') as file:
burger_col = (line[3] for line in file) per_hour = (int(x) for x in burger_col if x != 'N/A')
print("Total burgers sold = ",sum(per_hour))
4. 生成无限序列
生成器可以生成无限项目。无限序列无法包含在内存中,由于生成器一次只生成一个项目,考虑以下示例:
def infinite_sequence():
num = 0
while True:
yield num
num += 1
for i in infinite_sequence():
print(i)
输出:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.........
..........
315
316
317
Traceback (most recent call last):
File "C:\Users\DEVANSH SHARMA\Desktop\generator.py", line 33, in <module>
print(i)
KeyboardInterrupt
在本教程中,我们学习了关于Python生成器的内容。