看完这篇,你就知道Python生成器是什么
生成器是 Python 低级开拓者最难领略的观念之一,虽被认为是 Python 编程中的高级技术,但在各类项目中可以到处见到生成器的身影,你得不得去领略它、利用它、甚至爱上它。
提到生成器,总不行制止地要把迭代器拉出来比拟着讲,生成器就是一个在行为上和迭代器很是雷同的工具,假如把迭代器比作 Android 系统,那么生成器就是 iOS,二者成果上差不多,可是生成器更优雅。
什么是迭代器
顾名思义,迭代器就是用于迭代操纵(for 轮回)的工具,它像列表一样可以迭代获取个中的每一个元素,任何实现了 __next__ 要领 (python2 是 next)的工具都可以称为迭代器。
它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计较(lazy evaluation)方法返回元素,这正是它的利益。好比列表含有中一千万个整数,需要占高出400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是比及挪用 next 要领时候才返回该元素(按需挪用 call by need 的方法,本质上 for 轮回就是不绝地挪用迭代器的next要领)。
以斐波那契数列为例来实现一个迭代器:
class Fib: def __init__(self, n): self.prev = 0 self.cur = 1 self.n = n def __iter__(self): return self def __next__(self): if self.n > 0: value = self.cur self.cur = self.cur + self.prev self.prev = value self.n -= 1 return value else: raise StopIteration() # 兼容python2 def __next__(self): return self.next() f = Fib(10) print([i for i in f]) #[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
什么是生成器
知道迭代器之后,就可以正式进入生成器的话题了。普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中尚有一种函数,用要害字 yield 来返回值,这种函数叫生成器函数,函数被挪用时会返回一个生成器工具,生成器本质上照旧一个迭代器,也是用在迭代操纵中,因此它有和迭代器一样的特性,独一的区别在于实现方法上纷歧样,后者越发简捷
最简朴的生成器函数:
>>> def func(n): ... yield n*2 ... >>> func <function func at 0x00000000029F6EB8> >>> g = func(5) >>> g <generator object func at 0x0000000002908630> >>>
func 就是一个生成器函数,挪用该函数时返回工具就是生成器 g ,这个生成器工具的行为和迭代器长短常相似的,可以用在 for 轮回等场景中。留意 yield 对应的值在函数被挪用时不会立即返回,而是挪用next要领时(本质上 for 轮回也是挪用 next 要领)才返回
>>> g = func(5) >>> next(g) 10 >>> g = func(5) >>> for i in g: ... print(i) ... 10
那为什么要用生成器呢?显然,用生成器在逼格上要比迭代器高几个品级,它没有那么多冗长代码了,并且机能上一样的高效,为什么不消呢?来看看用生成器实现斐波那契数列有多简朴。
def fib(n): prev, curr = 0, 1 while n > 0: n -= 1 yield curr prev, curr = curr, curr + prev print([i for i in fib(10)]) #[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
生成器表达式
#p#分页标题#e#
在前面一期「这样写代码更优雅」的文章内里曾经先容过列表推导式(list comprehension),生成器表达式与列表推导式长的很是像,可是它俩返回的工具纷歧样,前者返回生成器工具,后者返回列表工具。
>>> g = (x*2 for x in range(10)) >>> type(g) <type 'generator'> >>> l = [x*2 for x in range(10)] >>> type(l) <type 'list'>
前面已经先容过生成器的优势,就是迭代海量数据时,显然生成器更符合。