自从PEP 255引入以来,生成器就一直是python的重要组成部分。
python中的Generator是一种特殊的例程,可用于控制循环的迭代行为。生成器类似于返回数组的函数。生成器具有参数,我们可以调用它并生成数字序列。但是,与返回整个数组的函数不同,生成器一次只需要一个值,而占用的内存更少。
任何带有关键字“ yield”的python函数都可以称为生成器。普通的python函数从第一行开始执行,一直持续到返回return语句,异常或函数结束为止,但是,在函数作用域内创建的任何局部变量都将被破坏并且无法进一步访问。在生成器遇到yield关键字的情况下,函数的状态被冻结,所有变量都存储在内存中,直到再次调用生成器为止。
我们可以根据迭代器使用generator,也可以使用“ next”关键字显式调用它。
通常是Python中的生成器:
用def关键字定义
使用yield关键字
可能包含几个yield关键字。
返回一个迭代器。
def generator_thr_iter(): yield 'xyz' yield 246 yield 40.50 for i in generator_thr_iter(): print(i)
输出结果
xyz 246 40.5
def generator_thr_iter(): yield 'xyz' yield 246 yield 40.50 >>> g = generator_thr_iter() >>> g.__next__() 'xyz' >>> g.__next__() 246 >>> g.__next__() 40.5 >>> g.__next__() Traceback (most recent call last): File "<pyshell#39>", line 1, in <module> g.__next__() StopIteration
我们可以将生成器想象为一个生成器,一个生成器一个一个地返回多个项,而不是一次返回所有项,并且生成器功能被暂停直到请求下一个生成项。
考虑一下,我们要计算从1到n的数字的平方,其中n确实是一个大数字,这样创建一个最多为'n'的数字列表将占用整个系统内存空间。
没有生成器,我们的方法将类似于-
>>> n= 200000000000 >>> number_list = range(1, n+1) >>> for i in number_list: print(i*i)
上述方法将消耗大量系统内存。更好的方法是在不创建数字列表的情况下遍历数字,以免占用系统内存。这是发电机的使用。
我们的生成器程序将是-
def num_generator(n): num =1 while True: yield num if num == n: return else: num += 1 for i in num_generator(200000000000): print (i*i)
因此,在上述方法中,当首次初始化for循环时,将调用num_generator并将n = 200000000000的值存储在内存中,并且将num = 1初始化并输入到永久循环的while循环中。然后遇到yield num,这时while循环被冻结,所有局部变量都存储在内存中。由于num = 1,yield num返回到for循环并分配给I,在此打印1(i * i)并进行对num_generator的下一次调用。
现在,执行从先前冻结的点开始,因此它执行了num == n(1 == 200000000000)行,这是错误的,因此执行了num + = 1,从而得出num = 2,而while循环为再次执行,过程继续。
最后,在执行循环直到n = 200000000000时,当产生200000000000时,将执行下一行'num == n'(200000000000 == 200000000000),因为确实如此,将执行return语句。
因此,当生成器执行return语句或遇到异常或到达生成器的末尾时,将引发“ StopIteration”异常,并且for循环迭代此刻停止。因此,在上面,我们能够打印最大为200000000000的数字的平方,而无需创建大量的数字,而这些数字本来会占用大量的系统内存。
考虑以上情况,我们可以在日常编程实践中使用生成器来创建更高效的程序。