大家可以先跳转到机器人那一块,上机跑一跑效果,感受一下在钻研代码,如果不会再去看我所罗列到的知识点。

做出专属于你的图灵机器人

流程:
一:剖析一下生成器对象 二:类比java讲解py中的协程
三:做出专属于你的图灵机器人

一:剖析一下生成器对象

先通过下面的例子来看一下什么是生成器?

def gen():
    print ('start ..')
    for i in range(3):
        yield i
    print ('end...')
G = gen()
#打印类型
print (type(G))
<class 'generator'>

上面表示G是一个生成器对象,我来看看里面具体有什么?

dir()函数,能够显示一个模块定义的所有成员

print(dir(G))
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']

这里有很多成员,我们着重关注四个函数

  • close()
  • next()
  • send()
  • throw()
    下面重点阐明:

二:类比java讲解py中的协程

如果大家有java基础,就会敏感发现上述的方法和线程是一样的。

只是在py中,我们叫他 协程

可以认为协程是一种轻量级的线程或者微线程,可以运行多个函数,让这几个函数看起来似乎是同一时间运行,

但是比线程又有一些优点,比如不用占大量的内存,开销小,也不用考虑线程的安全

1.send()函数

send()函数用于传递参数,实现与生成器的交互,当程序运行到receive=yield时,就会被挂起(停止),等待生成器调用send方法,

这时候当外部调用send函数时,发送数据变量,数据变量就会传递到received里面

示例:

def demo():
    while True:
        received =yield
        print('Received:{}'.format(received))
        
Demo = demo()
next(Demo)
Demo.send('First')
Demo.send('Second')
Received:First
Received:Second

对于生成器需要理解以下知识点:

yield :yield可以当做一个暂停/开始的信号,有yield的函数就是一个generator,yield x 整体就是一个表达式,代码运行到yield就会暂停

还有疑惑或者想深入了解可以看一下这篇文章:python yield用法总结

next():遇到表达式时暂停,返回yield表达式中的参数x,此时搁置yield表达式,再次调用next时,就会跳过yield,直接执行后面的代码

对于上述代码,做以下解释:

a).demo函数里面有一个死循环,里面有一行关键的代码,received=yield
(有yield就可以看成是生成器),这个received接受的就是函数从外部发送过来的数据

b).外部函数一开始就会生成一个构造器对象,也就是这行语句:Demo = demo()

c).最关键的就是一定要调用next这个方法,让生成器推进到第一条yield表达式

d).接下来我们就可以把yield操作和send操作结合起来,可以获取外界所输入的数据,然后用一套流程去进行处理:不断获取,不断回复

2.throw()函数

throw函数主要是向生成器发送一个异常,可以结束系统以及我们自定义的异常,并按照我们的要求输出(和java的try catch几乎一样)

我们使用以下几步来理解此方法:

  • a.创建生成器对象G
  • b.执行next(G)并打印结果,我们会得到第一个yield里缓存的结果’First’,并且停留在yield 'Second’之前
  • c. 抛出一个异常类ValueError(注意ValueError是类不是字符串),当生成器收到异常直接跳过 yield ‘Second’进入except部分,打印出’Catch the TypeError’
  • d. 执行next(G)并打印结果,我们会回到while头部,并且消耗掉第一个yield ‘Frist’,执行yield ‘Second’

示例代码如下:

def YiChang():
    while True:
        try:
            yield 'First step'
            yield 'Second step'
        except TypeError:
            print('Catch the TypeError')
        except ValueError:
            print('Catch the ValueError')
            
E = YiChang()
print(next(E))
E.throw(ValueError)
print(next(E))
结果如下:
First step
Catch the ValueError
Second step
3.close()函数

close用于停止生成器,如果停止之后再调用next,就会引发StopIteration错误

示例代码:

def demo():
    while True :
        received = yield
        print('Receive:{}'.format(received))
        
try:
    Demo = demo()
    next(Demo)
    Demo.close()
    Demo.send('现在还能输出吗')
except (StopIteration):
    print('Catch the StopIteration')
输出:
Catch the StopIteration

当生成器对象Echo调用完close()之后,再调用send(‘现在还能输出吗’)就会抛出一个异常StopIteration,然后被我们捕捉到了,没有打印出我们想要的语句,代表已经被关了

三.做出专属于你的图灵机器人

了解了上述知识点,我们通过生成器来做一个智能聊天机器人吧

  • 1)创建一个聊天机器人生成器函数,可以认为是后台的一个线程函数

注意:当检索到输入包含此语句单词就会输出

def chat_robot():
    res = ''
    while True:
        receive = yield res
        if 'hi' in receive or '你好鸭'  in receive or '你好' in receive or 'hello' in receive:
            res = '你好鸭'
        elif'名字 ' in receive or '叫啥' in receive or '称呼' in receive:
            res = '我叫小国平'
        elif '年龄' in receive or '多大' in receive or 'old' in receive:
            res = '我十九岁啦'
        elif 'sex' in receive or '性别' in receive :
            res = '我是个男孩子哦~ '
        elif 'from' in receive or '来自' in receive or 'where' in receive or '故乡' in receive :
            res = '我来自甘肃金昌,西北汉子一枚'
        elif '现在在哪读书 ' in receive or '现在在哪' in receive :
            res = '我现在在湖南长沙哦'
        elif '体重' in receive or '你多重呀' in receive:
            res = '我的体重是65千克'
        elif 'height' in receive or '身高' in receive:
            res = '我的身高是 170 cm'
        elif 'hobby' in receive or '爱好' in receive or '喜欢什么' in receive:
            res = '我的爱好广泛哦,从笔墨中的丹青,到远方的故事,从书卷中的诗句,到未来的畅想,我有故事也有酒,只差一个听故事的你'
        elif 'bye' in receive or '拜拜' in receive or '再见' in receive:
            res = 'Bye bye, 期待下一次和你再见哦!'
        elif 'handsome' in receive or 'beautiful' in receive or '帅气' in receive or '好看' in receive:
            res = '你真帅气!你最帅气啦!'
        elif 'girlfriend' in receive or '女朋友' in receive or '单身' in receive:
            res = '这个问题太扎心了!'  
        elif 'fuck' in receive:
            res = '来呀!小宝贝'  
        elif '怎么学' in receive:
            res = '亲,推荐百度一下哦'  
        elif '要你干' in receive:
            res = '呜呜呜,人家只能陪你聊天解闷,至于其他功能,小主人还没开发呢' 
        else :
            res = "对不起,我不能理解你所说的,可以重新表述一下吗"
  • 2).前台不断的获取用户的输入,然后利用协程发送给后台处理
Chat = chat_robot()
next(Chat)

while True:
    mess = input('Please input:')
    if mess == 'q' or mess == 'Q':
        print( 'Robot exit..')
        break
        
    response = Chat.send(mess)
    print('Robot:{}'.format(response))
    if 'Bye bye' in response:
        break
Chat.close()

大家可以改一下自己的语料库,就做出专属于自己的聊天机器人啦