Python基础-day14-迭代器
""" 任何数据类型,只要含有__iter__方法,那它就是可迭代的。 这就是 可迭代协议 任何数据类型,只要含有__iter__和__next__方法,那它就是迭代器。 这就是 迭代器协议 """ from collections import Iterable from collections import Iterator class A: def __iter__(self): pass def __next__(self): pass a = A() print(isinstance(a, Iterable)) print(isinstance(a, Iterator))
迭代器有一个__next__方法,调用迭代器的__next__方法,我们可以获取迭代器中的值。
每调用一次,就获取一个值,直到取完。
之所以能对一个对象使用for循环,是因为这个对象是可迭代的,也就是说,当一个对象含有__iter__时,就能用for循环。
通过编写生成器,我们自己也能实现迭代器。(生成器的本质是迭代器)
创建生成器的方式1:生成器函数。
# 一个函数只要含有yield关键字,那么这个函数就是生成器函数。
# return返回值后,函数结束。
# yield返回值后,函数不结束,而是停在那里。
# yield不能和return共用。
def generator(): print(1) yield 'a' ret = generator() print(ret)
打印:
<generator object generator at 0x02AF9F30>
这说明了:含有yield的函数就是生成器函数,因此返回了一个对象。
def generator(): print(1) yield 'a' ret = generator() value = ret.__next__() # 调用一次,生成器就走一步,遇到yield后就停下脚步,返回的'a'交给了value print(ret) print(value)
打印结果为:
1
<generator object generator at 0x03979F30>
a
def generator(): print(1) yield 'a' print(2) yield 'b' ret = generator() value1 = ret.__next__() value2 = ret.__next__() print(value1, value2)
打印结果:
1
2
a b
每执行一次__next__,代码就走一下,这一下包括打印1,返回'a',然后就停止不动,直到再次调用__next__。
使用for循环:
def generator(): print(1) yield 'a' print(2) yield 'b' ret = generator() for i in ret: print(i)
打印:
1
a
2
b
这就是利用for来遍历生成器对象,从而打印结果。(为什么这里的i就代表了1和'a'呢,而前面的__next__必须要用一个变量来接收返回值'a'呢?)
小功能:
""" 实时监听文件的输入 """ def tail(filename): f = open(filename, encoding='utf-8') while True: line = f.readline() if line and line != '\n': print(line.strip()) tail('test.log')
这种方式很耗资源,在while循环中,它无限循环,给资源造成了很大的压力,这种循环读取文件的方式太暴力了。
比较好的方式是:当文件修改了,才去读取文件,而不是有事无事都跑去问,这多累啊。
这就遇到一个问题:是否改变,也是需要不断的去检查,这也是会涉及到无限循环?
能否用阻塞的形式呢?也就是如果文件没有变化,那么就阻塞在那里,代码不执行,一旦变化,再执行。
双下划线方法:很少直接调用,一般情况下,是通过其他语法触发的。
比如__next__是通过for循环触发的。
比如__add__是通过 + 符号触发的。
调用可迭代对象的__iter__方法,就能得到一个迭代器。
ret = 可迭代对象.__iter__
这里的ret就是一个迭代器。
迭代器的特点:
一个迭代器只能从头到尾取一次,不能重复取,不能往回取,这样可以节省内存空间。

对于迭代器,我们有三种方法来获取它里面的值:

for循环和__next__,前面已经说明了。
ret = generator() li = list(ret) # 利用list()强制转换迭代器对象 print(li)
返回结果:
1
['a']

现在再来介绍send():


send的作用同__next__。
只不过,代码在开始执行前,会先接受send发来的值。接收的位置就是上一次暂停的地方。
如上图所示。

yield from:
 
 
创建生成器的方式2:生成器表达式。






{10: 'a', 34: 'b'}
都是在内部先遍历,然后再做一些处理,最后才得出结果。
跟我们写逻辑是一样的,只不过推导式是简化了的方法。


列表推导式
字典推导式
集合推导式
生成器推导式
唯独元祖没有推导式

代码要写的易懂且简洁,这需要很深的功底。


 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号