Python_day06--生成器Generators、生产消费者模型、协程、迷你机器人

一、生成器

1、生成器

前面一章我们说过列表生成器;

li = [i for i in range(30) if i%2==0]

得到下面的结果;

我们遍历1~30,找出其中的所有偶数,输出的结果为一个列表;

如果我们用生成式再呈现一次呢;

g = (i for i in range(100) if i%2==0)

我们能看到,生成器的返回值不在是 一个列表,而是一个生成器,我们不能直接打印,而是需要去遍历这个生成器;

2、查看生成器内容的两种方式

方式一:

注意:在python2中,我们用g.next();python3中 g.__next__方法( ) 或 next(g)

python2.x中:

python3.x中:

next( ) 每次只执行一次,并且等待下一次的指令;生成器并不会结束

方式二:for循环

g = (i for i in range(30) if i%2==0)

for i in g:
    print(i,end=',')

方式三:

g = (i for i in range(30) if i%2==0)
while True:
    try:
        print(g.__next__(),end=',')
    except StopIteration:
        break


这里我们再强调一次,怎么去看一个对象是否为可迭代对象:

from collections import Iterable

g = (i for i in range(30) if i%2==0)
print(isinstance(g, Iterable))

3、yield关键字

当在函数中看到yield关键字, 那么这个函数调用的返回值是一个生成器;

Yield的用法有点像return;

1)函数中使用yield,可以使函数变成生成器。一个函数如果是生成一个数组,就必须把数据存储在内存中,如果使用生成器,则在调用的时候才生成数据,可以节省内存。

2)生成器方法调用时,不会立即执行。需要调用next()或者使用for循环来执行。使用for循环不需要自己捕获StopIteration异常。使用next()方法,当生产器方法执行结束会抛出StopIteration异常(只要不是使用yield返回数据,都会抛出StopIteration异常)。

3)yield不仅可以返回值,也可以接收值。

4)调用生成器send方法传递数据时,必须先调用next(c)或者c.send(None)方法,执行到yield语句,等待接收数据。否则会报错。

例:

def fib(num):
    a, b, count = 0, 1, 1  # 0, 1
    while count <= num:
        yield b
        a, b = b, a + b  #a=2, b=3
        count += 1

g = fib(10)
for i in g:
    print(i,end=',')

例2、

def fun():
    a = "world"
    print("hello")
    print(1)
    yield 2
    print(3)
    yield 4

g = fun()
print(g)

print(g.__next__())

通过上面两张图片的对比,我们发现生成器在被调用时,首先他会运行至yield关键字这里,并且在这里等待下一次的调用,并不会结束函数;直到我们第二次调用时自动到下一个yield关键字继续等待,或运行至函数结束。

二、生产者、消费者模型

例:下面以简单的包子的制作与购买制作模型;

def consumer(name):
    print("%s准备买包子....." %(name))
    while True:
        kind = yield
        print("%s已经购买%s口味包子....." %(name, kind))


def producer(name):
    c1 = consumer("张三")
    c2 = consumer("李四")
    c1.__next__()
    c2.__next__()
    print(c1 is c2)

    print("厨师%s准备制作包子......" %(name))
    for kind in ['酸菜', '牛肉','香菇青菜','豆腐粉条']:
        time.sleep(random.random())    #导入时间模块,让时间在这里随机的停0~1秒,模拟包子制作的过程;
        print("%s制作了%s口味的包子" %(name, kind))
        c1.send(kind)
        c2.send(kind)

producer(' 我 ')


这里我们要着重说明一下yield 和 send,我们先用一个一段代码理解:

def MyGenerator():
    v = yield 1  # yield:语句执行到yield就停止了 所以刚开始运行到这一句的时候v没有赋值为1,等到send(5)时(yield 1被视为传入的参数5) 此时这一句被执行,v=5
    v = yield v
    b = yield v
    v = yield v
    c = yield b


gen = MyGenerator()
print(next(gen))
print(gen.send(5))  # v = yield 1 ->v = 5 ,先yield v,未执行v = 这里的赋值语句
print(gen.send(7))  # v = yield v ->v = 7 ,先yield v,未执行b = 这里的赋值
print(gen.send(5))  # b = yield v ->b = 5 ,yield v(=7) ,未执行v = 这里的赋值
print(gen.send(7))  # v = yield v ->v = 7 ,yield b(=5) 结束

小作者本人也还在研究之中,yield和send的理解和使用方法,这个问题先放在这里,待我搞清楚再回来作补充.........

三、协程

协程是一种允许在特定位置暂停或恢复的子程序——这一点和生成器相似。但和生成器不同的是,协程可以控制子程序暂停之后代码的走向,而生成器仅能被动地将控制权交还给调用者。

例:假设有两个子程序main和printer。printer是一个死循环,等待输入、加工并输出结果。main作为主程序,不时地向printer发送数据。

线来看一段代码

def printer():
    counter = 1
    while True:
        text = yield
        print('[%d] %s' %(counter, text))
        counter += 1

def main():
    p = printer()
    next(p)
    for i in range(10):
        p.send('张三')
        p.send('李四')
        p.send('王麻子')
main()

printer函数做一个子函数,yield这里理解为等待send传参数,当main函数传入‘张三’这个参数时,printer函数开始进入循环,直到‘张三’这个参数10次传输完成截至,接着到下一个send=‘李四’传入printer函数........以此类推直到最后一次‘王麻子’传参结束。整个循环全部结束。

注意:我们在使用yield 和 send时,在send语句前一定要使用next(函数名),否则系统会报错;

四、迷你机器人

我们一般使用的机器人对话都是由迷你型机器人衍生出来的,没有真正意义上的实现科幻电影中的那些只能场景;

def robot():
    say = ''
    while True:
        s = yield say
        if 'age' in s:
            say = '爸爸25了'
        elif 'name'in s:
            say = '求我阿,求我我就告诉你'
        elif 'birthday' in s:
            say = '明天就是爸爸的生日啦'
        elif 'hello'in s:
            say = 'hello too'
        else:
            say = '我什么都不知道!'



def main():
    g = robot()
    next(g)
    while True:
        user_send = input('我:')
        robot_send = g.send(user_send)
        print('robot:%s'%(robot_send))

main()

今天早上2018/05/10,我看到谷歌推出了一款真正的交互式机器人,抛弃了传统的siri,真正意义上的称的上为人工智能,现场演示:发布会上,用户对Google Assistant说:我想剪头发。Google Assistant接到指令后直接帮你打电话预约!!!........

看完了整场演示我为之震惊,人工智能已经在我们的身边潜伏着,随着时代的发展也许一个不留神你就被机器人无情的踩在脚下;还记得那次人机大战吗?阿尔法和李世石的围棋大战,当天阿尔法输掉了比赛,疲惫的李世石早已睡下,世界都以为人工智能不过是一场虚惊。然而,当天晚上阿尔法和自己下了一百万盘围棋。当第二天太阳升起,李世石还是那个李世石,但是阿尔法早已有了天翻地覆的变化。废话先写这么多吧,我的感受颇深,毕竟这里谈论的是技术,就不多作感情上的宣泄李。






猜你喜欢

转载自blog.csdn.net/biu_biu_0329/article/details/80266432