一.生成器
在介绍生成器表达式之前,先看下列表表达式:
1 >>> l = [i for i in range(50) if i % 2] #生成数字50内所有奇数列表 2 >>> l 3 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]
生成器表达式和列表表达式一样,不过是()起来而不是[],成器表达式产生的生成器,它自身是一个可迭代对象,同时也是迭代器本身。例如:
1 >>> gen = (i for i in range(50) if i % 2) 2 >>> gen 3 <generator object <genexpr> at 0x7f2f415eb2b0> 4 >>> gen.__next__() #使用next()方法可以访问下一个元素 5 1 6 >>> gen.__next__() 7 3 8 >>> gen.__next__() 9 5 10 >>> gen.__next__() 11 7
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器
1 def cash_out(amount): 2 while amount >0: 3 amount -= 1 4 yield 1 5 print("擦,又来取钱了。。。败家子!") 6 ATM = cash_out(5) 7 print("取到钱 %s 万" % ATM.__next__()) 8 print("花掉花掉!") 9 print("取到钱 %s 万" % ATM.__next__()) 10 print("取到钱 %s 万" % ATM.__next__()) 11 print("花掉花掉!") 12 print("取到钱 %s 万" % ATM.__next__()) 13 print("取到钱 %s 万" % ATM.__next__()) 14 print("取到钱 %s 万" % ATM.__next__()) #到这时钱就取没了,再取就报错了 15 print("取到钱 %s 万" % ATM.__next__())
yield的主要作用就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以重新调用这个函数,从上次yield的下一句开始执行。
二。迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
生成一个迭代器:
1 >>> a = iter([1,2,3,4,5,6]) 2 >>> a.__next__() 3 1 4 >>> a.__next__() 5 2 6 >>> a.__next__() 7 3 8 >>> a.__next__() 9 4 10 >>> a.__next__() 11 5 12 >>> a.__next__() 13 6 14 >>> a.__next__() 15 Traceback (most recent call last): 16 File "<stdin>", line 1, in <module> 17 StopIteration
判断一个对象是否是iterable对象:
1 from collections import Iterable 2 >>> a 3 <list_iterator object at 0x7f2f410ecfd0> 4 >>> from collections import Iterable 5 >>> print(isinstance(a,Iterable)) 6 True 7 >>> print(isinstance({},Iterable)) 8 True 9 >>> print(isinstance('fdsffdsf',Iterable)) 10 True 11 >>> print(isinstance(100,Iterable)) 12 False
总结:
1.生成器都是Iterator对象,但list,tuple,str虽然是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象,因为python的Itertor表示的是一个数据流,可以被next。
2.凡是可作用于for循环的对象都是Iterable类型;凡是可作用于next()函数都是Itertor
3.经过测试生成器和列表生成器,两者占用cpu和运行速度不差上下,但是生成器只占用4g内存的0.3%,列表生成式占2.4%