用yield的函数是生成器函数(generator),即函数会返回一个生成器
代码:
输出:
注意:
ret = generator()
这句并不会执行generator里面的语句(与return不同,用return会直接触发print语句,但yield不会),因为用了yield,就认定该函数是一个生成器函数,只会返回一个生成器。
1和a的输出,是在print(ret.__next__())执行的时候才触发的
我们用print(dir(ret))看一下生成器具体有什么方法:
可见生成器有__iter__,__next__方法,说明他是可迭代的对象,使用方法:
yield 优点:
当调用一次的时候才生成一个,比较省内存空间
缺点:
当数据较大的时候,因为找地址的时间会更久,所以速度会慢一些
补充:
怎么看待生成器函数不是执行语句呢?看下面这个例子
如果使用return,必然执行函数语句,再执行for循环,这时while形同虚设,在读取一行后,把值返回给了line,再for迭代line,结束程序
输出:
如果使用yield,这个时候我们的line是一个生成器,只有在for循环中才开始调用generator函数
每一次for,都会执行一次generator函数,返回每一行的数据,即在yield语句后,下一次循环又从while True开始执行,再读取一行数据,输出。每次从上一次结束再调用时,生成器函数的内部变量、指令指针、内部求值栈等内容和上一次结束时完全一致。(yield在生成一个元素后,会记住迭代的位置并将当前的状态挂起,return则是直接退出函数,)
所以我们可以做一个实时的监控文件内容的程序:
============================================================================
send用法:
send可以先传进一个参数,随后的执行与__next__方法一样
代码示例:
输出:
执行i.__next__()方法,第一次调用了generator,输出1,此时停留在执行完右边的 “ yield返回的‘a‘ ”,输出a
第二次调用send,先传进一个值给content,输出2, hello,再调用__next__()获取yield返回的’b‘,输出b
注意:第一次调用必须使用__next__,如果使用send,没有参数接收(send先传参再执行)
最后一个yield不需要用send,自行理解。
============================================================================python3 field特性:
可用 yield from 代替,等价于