python的迭代器和生成器

本文参考 景霄大神的《python核心技术与实战》python

一 、python中的容器、可迭代对象、迭代器的使用


 容器: python中一切皆对象, 对象的抽象就是类, 而对象的集就是容器,因此列表, 元祖,字典等都是容器,而且全部的容器都是能够迭代的(iterable)

  迭代器: 迭代器(iterator)提供了next的方法, 调用这个方法会获得迭代器的下一个对象,直到取完抛出StopIteration错误类型,因此能够经过可迭代对象调取next方法完成遍历迭代器。

能够经过isinstance校验是否为可迭代对象isinstanstance(obj, lterable)

二 、生成器


 通俗的解释是懒人的迭代器, 在使用迭代器构成中全部的元素都会直接一次保存在内存中,可是生成器全部的元素经过调取next动态生成, 直观的感觉就是节省了不少资源

 举例:生成一亿的迭代器[for i in range(10000000000)],可是在实际运用中并不会使用到每一个元素, 这个时候用生成器替代迭代器会更高效,也并不会报OOM异常, 生成器写法 ( for i in range(100000000))

 做用:迭代器和生成器二者区别还不止内存消耗,迭代器是有穷的,可是由于生成器是动态生成元素,理论上它是能够无限生成下一个元素的,

实例1 计算 (1 + 2 + 3 + ... + n)

def generator(k):
	i = 1
	while True:
		yield i ** k
		i = i + 1

gen = gennerator(1)
def get_sum(n): 
	sum = 0
	for i in range(n):
		_next = next(gen)
		print(_next)
 
复制代码
 就跟这个公式同样, n能够取无穷, 一样理论上生成器也能够取无穷, 上述代码用yield暂停了函数,而且跳转到next()函数, i ** k 即为next返回值, yield的用法还有不少, 能够代替线程用协程的方法完成函数块的切换,省去了线程间切换消耗的资源,能够用send激活, 这边讲了其中一种用法, 一样它也就是用next激活了生成器。

实例2 在列表中查找某个数字的位置

def func1(list, k):
	out_list = []
	for i, num in enumerate(list):
		if num == k:
			print('fonud it ', i)

def func2(list, k):
	for i, num in enumerate(list):
		if num == k:
			yield i

复制代码

ps: func2就是生成了一个迭代器对象, 再转list就能够了, 可让代码更加有可读性。markdown

实例3 查找列表中是否包含子列表

def is_instance(check_list, list):
	list = iter(list)
	
	return all( i in list for i in check_list) # all()函数必须全部返回均为True才会返回True
复制代码

3、总结

  •  容器是可迭代对象, 可迭代对象调用iter()函数能够获得一个迭代器, 迭代器经过next()获得下一个元素, 从而支持遍历, 注意点: 迭代器遍历只可使用一次,缘由是由于迭代器会存到缓冲区内, 经过移动指针来消耗缓冲区, 随时读取,可是读过一次以后指针就在缓冲区的末尾, 因此不可重复读取。
  •  生成器是一种特殊的迭代器,合理使用生成器能够下降内存占用,优化程序结构,提升程序运行速度
  •  生成器也是在python2中协程的一种重要的实现方式(在python中因为GIL的存在每每使用多进程+协程的方式实现并发), 而在python3.5以上引用了async await语法糖
相关文章
相关标签/搜索