'yield'和生成器解释

本片笔记学习自:Improve Your Python: 'yield' and Generators Explained

A Python generator is a function which returns a generator iterator (just an object we can iterate over) by calling yield. yield may be called with a value, in which case that value is treated as the "generated" value. The next time next() is called on the generator iterator (i.e. in the next step in a for loop, for example),Rthe generator resumes execution from where it called yield, not from the beginning of the function. All of the state, like the values of local variables, is recovered and the generator contiues to execute until the next call to yield.

  • 子程序(subroutine)
    一些时候,我们想要创建一个可以不断得到一系列值的函数,而不是一个值(return),为了做到这样子,这个函数首先要能够保存上下文。
    注意return、yield的不同:return返回None或者某个值,并且将控制权归还到调用前附近的代码段;yield则更多地是我们希望连续不断的获取。
    有yield能力的“函数”叫做生成器.

  • 生成器的作用
    动态生成一系列的数。

  • 迭代器、生成器
    生成器是一种迭代器,生成器必须要有next().

To get the next value from a generator, we use the same built-in function as for iterators: next().next() takes care of calling the generator's next() method). Since a generator is a type of iterator, it can be used in a for loop.

为了从生成器中获取一个值,我们必须使用相同的内嵌函数next(),这个函数会调用生成器/迭代器的next()方法,我们可以在for循环中使用生成器。

The easiest way to remember what yield does is to think of it as return (plus a little magic) for generator functions.**

  • 生成器的例子:
>>> def simple_generator_function():
>>>    yield 1
>>>    yield 2
>>>    yield 3

>>> for value in simple_generator_function():
>>>     print(value)
1
2
3

>>> our_generator = simple_generator_function()
>>> next(our_generator)
1
>>> next(our_generator)
2
>>> next(our_generator)
3
  • 当生成器函数退出的时候会有一个StopIteration异常。

  • send:发送数据给生成器。
    有时我们需要跟生成器进行一些交互,我们不仅仅要从生成器中得到一些值,还想给生成器发送一些值。

假设我们要打印出大于1、10、100、1000...等的最小整数,代码如下,###########表示打印调试信息,可以不看:

import math

def is_prime(number):
    if number > 1:
        if number == 2:
            return True
        if number % 2 == 0:
            return False
        for current in range(3, int(math.sqrt(number) + 1), 2):
            if number % current == 0:
                return False
        return True
    return False

def get_primes(number):
    print(str(number)+'-1')    ###########
    while True:
        print(str(number)+'-2') ###########
        if is_prime(number):
            print(str(number)+'-3') ###########
            number = yield number
            print(str(number)+'-4') ###########
        number += 1
        print(str(number)+'-5') ###########

def print_successive_primes(iterations, base=10):
    prime_generator = get_primes(base)
    prime_generator.send(None)
    for power in range(iterations):
        print(prime_generator.send(base ** power))

print_successive_primes(10)

首先我们只调用prime_generator = get_primes(base)启动生成器,这个时候我们没有做什么,仅仅只是启动生成器;
接着我们调用prime_generator.send(None),打印出如下的信息,这说明发送None只是为了让生成器第一次运行到yield语句(包括yield)。

10-1
10-2
11-5
11-2
11-3

接着我们调用10次prime_generator.send(base ** power),每次都是主流程发送值过去,生成器收到的同时发送一个数据回来,主流程收到数据。这个过程就像调用函数一样,只不过这次我们可以加参数进去了!!!

  • 生成器的威力
import random

def get_data():
    """Return 3 random integers between 0 and 9"""
    return random.sample(range(10), 3)

def consume():
    """Displays a running average across lists of integers sent to it"""
    running_sum = 0
    data_items_seen = 0

    while True:
        data = yield
        data_items_seen += len(data)
        running_sum += sum(data)
        print('The running average is {}'.format(running_sum / float(data_items_seen)))

def produce(consumer):
    """Produces a set of values and forwards them to the pre-defined consumer
    function"""
    while True:
        data = get_data()
        print('Produced {}'.format(data))
        consumer.send(data)
        yield

if __name__ == '__main__':
    consumer = consume()
    consumer.send(None)
    producer = produce(consumer)

    for _ in range(10):
        print('Producing...')
        next(producer)

要理解以上的代码,可以将代码分成两部分的功能:一部分是生成,一部分是消费。
主函数里面启动生产,每生产一个喂给消费者一个,消费者消费后得出一个结果。主函数控制生产,生产控制消费。
produce是一个生成器,yield只是为了让produce运行一次停一次,好将生成数据进行消费;
consume也是一个生成器,这里yield只是为了得到数据,然后消费,然后又继续等待数据,还是蛮被动的。

  • 总结:
    There are a few key ideas I hope you take away from this discussion:
    generators are used to generate a series of values
    yield is like the return of generator functions
    The only other thing yield does is save the "state" of a generator function
    A generator is just a special type of iterator
    Like iterators, we can get the next value from a generator using next()
    for gets values by calling next() implicitly
    I hope this post was helpful. If you had never heard of generators, I hope you now understand what they are, why they're useful, and how to use them. If you were somewhat familiar with generators, I hope any confusion is now cleared up.

  • 拓展阅读:
    看完这篇,你就知道Python生成器是什么

你可能感兴趣的:('yield'和生成器解释)