python yield

一。深入研究

>>> def get_0_1_2():
...   yield 0
...   yield 1
...   yield 2
...
>>> get_0_1_2
<function get_0_1_2 at 0x00B2CB70>       #函数类型

>>> generator = get_0_1_2()
>>> generator
<generator object get_0_1_2 at 0x00B1C7D8>  #生成器

>>> generator.next()    #第一次调用生成器的next方法时,生成器才开始执行生成器函数(而不是构建生成器时),直到遇到yield时暂停执行
0
>>> generator.next()    #之后每次调用生成器的next方法,生成器将从上次暂停执行的位置恢复执行生成器函数,直到再次遇到yield时暂停
1
>>> generator.next()
2

>>> generator.next() #当调用next方法时生成器函数结束(遇到空的return语句或是到达函数体末尾),则这次next方法的调用将抛出StopIteration异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

因为直接调用next()到最后会抛出异常,所以一般使用for循环输出结果

>>> def test_return():
...      yield 4
...      return 0
...
  File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator

  作为生成器,因为每次迭代就会返回一个值,所以不能显示的在生成器函数中return 某个值,包括None值也不行,否则会抛出“SyntaxError”的异常,

但是在函数中可以出现单独的return,表示结束该语句。 

二。控制生成器

1.变量控制

 class Bank(): # 创建银行,构建ATM机,只要没有危机,就可以不断地每次从中取100
    crisis = False
    def create_atm(self):
        while not self.crisis:
            yield "$100"

2. send: Resumes the generator and "sends" a value that becomes the result of the current yield-expression

def consumer():
    print "consumer start..."
    result = None
    while True:
        s = yield result
        result = s.split(",")

c = consumer()  
#不调用则出错:TypeError: can't send non-None value to a just-started generator
print c.send(None)   # send(None) 或 next()启动协程

print c.send("a,b")  # 向协程发送消息
print c.send("c,d")
c.close()           # 关协程
# print c.send("e,f")  # 无法向已关闭的协程发送消息。

3.

def consumer():
    while True:
        d = yield
        if not d :break
        print "consumer: ", d

c = consumer() #创建消费者
c.send(None)   #启动消费者
c.send(1)      #生产数据,并提供给消费者
c.send(2)
c.send(3)
c.close()

三。示例

1.斐波那契数列

>>> def fibonacci():
...   a = b = 1
...   yield a
...   yield b
...   while True:
...     a, b = b, a+b
...     yield b
...
>>> for num in fibonacci():
...   if num > 100: break
...   print num,
...
1 1 2 3 5 8 13 21 34 55 89

看到while True可别太吃惊,因为生成器可以挂起,所以是延迟计算的,无限循环并没有关系。

2.读大文件

如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。

def read_file(path):
    size = 1024
    with open(path,'r') as f:
        while True:
            block = f.read(SIZE)
            if block:
                yield block
            else:
                return
原文地址:https://www.cnblogs.com/yuyutianxia/p/4116040.html