什么是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生成器的内容。

标签: Tkinter教程, Tkinter安装, Tkinter库, Tkinter入门, Tkinter学习, Tkinter入门教程, Tkinter, Tkinter进阶, Tkinter指南, Tkinter学习指南, Tkinter进阶教程, Tkinter编程