07-生成器:使用注意

目标

  • 知道使用 send 方法能够启动生成器、并传递参数
  • 能够说出协程中return的作用

1. 生成器中使用return

生成器客户以使用return 关键字,语法上没有问题,但是如果执行到 return 语句以后,生成器会停止迭代,抛出停止迭代的异常

In [30]: def fib(n):
   ....:     current = 0
   ....:     num1, num2 = 0, 1
   ....:     while current < n:
   ....:         num = num1
   ....:         num1, num2 = num2, num1+num2
   ....:         current += 1
   ....:         yield num
   ....:     return 'done'
   ....:

In [31]: F = fib(5)

In [32]: next(F)
Out[32]: 1

StopIteration: done

在使用生成器实现的方式中,我们将原本在迭代器__next__方法中实现的基本逻辑放到一个函数中来实现,但是将每次迭代返回数值的return换成了yield,此时新定义的函数便不再是函数,而是一个生成器了。{% em color="#2ff700" %}简单来说:只要在def中有yield关键字的 就称为 生成器{% endem %}

此时按照调用函数的方式( 案例中为F = fib(5) )使用生成器就不再是执行函数体了,而是会返回一个生成器对象( 案例中为F ),然后就可以按照使用迭代器的方式来使用生成器了。

    ....省略代码....    

    while current_index < n:

        # 定义要返回的值
        result = a
        # 生成新的 a、b值
        a, b = b, a+b
        # 让当前值+1
        current_index += 1
        print("-----------2222----------")
        yield result

        print("-----------3333------------")
        return "我是return的内容"

    ....省略代码....  

image-20180704214329736

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

    ....省略代码....   

# 生成器,生成斐波那契数列
fib = fibonacci(5)
# 第一次没有执行到 return,不用捕获异常
value = next(fib)
print(value)

try:
    # 如果无法取得数据,捕获异常
    value = next(fib)
    print(value)
except StopIteration as e:
    print("return信息:%s" % e.value)

image-20180704215259493

2. 使用send唤醒

我们除了可以使用next()函数来唤醒生成器继续执行外,还可以使用send()函数来唤醒执行。使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。

例子:执行到yield时,gen函数作用暂时保存,返回i的值; temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)

def fibonacci(n):
    # 定义斐波那契数列的前2个值
    a = 0
    b = 1

    # 定义当前的位置
    current_index = 0

    while current_index < n:
            # 定义要返回的值
            result = a
            # 生成新的 a、b值
            a, b = b, a+b
            # 让当前值+1
            current_index += 1


            parms = yield result
            print("send------", parms)
使用send

# 生成器,生成斐波那契数列
fib = fibonacci(5)
# 第一次没有执行到 return,不用捕获异常
# value = next(fib)
# print(value)
value = fib.send(None)
print(value)

value = fib.send("abc")
print(value)

value = fib.send("def")
print(value)

运行结果:

0
send------ abc
1
send------ def
1

Process finished with exit code 0

注意点:

使用send启动生成器的时候传入的参数必须是None,下次启动生成器的时候可以加上参数

提示: 一般第一次启动生成器使用next

总结:

  • 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
  • Python3中的生成器可以使用return返回最终运行的返回值,而Python2中的生成器不允许使用return返回一个返回值(即可以使用return从生成器中退出,但return后不能有任何表达式)。