阅读目录
楔子
假如有列表 lst = [1,2,3,4],如果想获取列表中的内容,我们有几种方式?
第一种,可以用索引取值;
第二种,可以用for循环,但是也存在特殊情况,比如整型不能用来for循环取值,举个例子:
for i in 123: print(i)
结果:
TypeError: 'int' object is not iterable
'int' object is not iterable 意思是: 整型是不可迭代的
那么,什么是可迭代的呢?
lst = [1,2] print(dir(lst))
结果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
from collections import Iterable l = [1,2,3,4] t = (1,2,3,4) d = {1:2,3:4} s = {1,2,3,4} print(isinstance(l,Iterable)) print(isinstance(t,Iterable)) print(isinstance(d,Iterable)) print(isinstance(s,Iterable))
结果:
True
True
True
True
结合上述代码,我们可以得出可迭代协议。可迭代协议简单来说,就是内部实现了__iter__方法.
也就是说,要想可迭代,内部必须要有__iter__方法,那么,__iter__做了什么呢?
print([1,2].__iter__())
结果:
<list_iterator object at 0x00000000027B7198>
iterator
迭代器
我们又得到了一个新的词语--迭代器。那么,什么是迭代器呢?先来看段代码:
l = [1,2,3,4] res = l.__iter__() print(res)
结果:
<list_iterator object at 0x00000000024115F8> #iterator 迭代器
再用dir()查看l和res可实现的方法:
print(dir(l))
print(dir(res))
结果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
再来看在res中,但不在l中的方法:
print(set(dir(res))-set(dir(l)))
结果:
{'__next__', '__length_hint__', '__setstate__'} #这些就是迭代器中特有的方法。
我们再来看看迭代器中特有的三种方法的功能。
print(res.__length_hint__()) # 迭代器中有多少个元素
结果: 4
res.__setstate__(2) # 控制迭代器从哪儿开始迭代
for i in res:
print(i)
结果:
3
4
print(res.__next__()) # 从迭代器中取下一个值
print(res.__next__())
print(res.__next__())
print(res.__next__())
结果:
1
2
3
4
那么,迭代器方法中能够实现一个一个取值的是什么?就是__next__
for循环,就是在内部调用了__next__从而实现了一个一个取值.
所以,迭代器遵循迭代协议:必须拥有__iter__和__next__方法
迭代器的特点:
1,具有iter和next方法;
2,通过多次执行next就可以获得迭代器中的所有的值;
3,迭代器中的值只能取一次
4,不取的时候值不出现
迭代器的优点就是:节省内存
关于迭代器的分析就到这里了,最后,我们再来分析一下,range()是不是一个迭代器呢?
print('__iter__' in dir(range(5))) print('__next__' in dir(range(5)))
print('__next__' in dir(range(5).__iter__()))
from collections import Iterator
print(isinstance(range(5),Iterator))
结果:
True
False
True
False
生成器
Python中提供的生成器:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器函数
所谓的生成器函数,就是包含了yield关键字的函数。
那么,生成器有什么好处呢?就是不会一下子在内存中生成太多数据。
假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。
def produce(): """生产衣服""" for i in range(2000000): yield "生产了第%s件衣服"%i product_g = produce() print(product_g.__next__()) #要一件衣服 print(product_g.__next__()) #再要一件衣服 print(product_g.__next__()) #再要一件衣服 num = 0 for i in product_g: #要一批衣服,比如5件 print(i) num +=1 if num == 5: break