一.列表生成式
列表生成式是Python 内置的非常简单却强大的可以用来创建 list的生成式
求出1-9的平方数,
print [ i**2 for i in range(1,10) if i !=0 ]
执行结果
[1,2,3,4,5,6,7]
list=[i for i in range(1,8)]
```
list= [1,2,3,4,5,6,7]
二.生成器
通过列表生成式,我们可以直接创建一个列表,受到内存限制,列表容量肯定是有限的;创建一个包含1万或者更多的元素的列表,占用很大的存储空间;而列表生成器可以很好地解决这个问题
1.生成器是什么?
在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的 list,从而节省大量的空间。在 Python 中,这种一边循环一边计算的机制,称为生成器(Generator)
那如果要取第8888个元素呢?for 循环,if
In [19]: for i in li:
....: if i == 8888:
....: print i
....:
8888
2.怎么创建生成器?
把一个列表生成式的 [] 改成 ()
使用g.next()方法依次读取元素(麻烦)
使用 for 循环(推荐)
2.1列表转化生成器方法一迭代器: iter(*)
li = [ 1,2,3,4]
print type(li)
g = iter(li)
print type(g)
执行结果li列表被转化生成器g了
<type 'list'>
<type 'listiterator'>
2.2方法二 *.__iter__()
ls = range(4)
print type(ls)
g = ls.__iter__()
print type(g)
查看类型,转化成了生成器
<type 'list'>
<type 'listiterator'>
定义一个列表
li = [ i for i in range(5)]
print li
print type(li),
执行结果:
[0, 1, 2, 3, 4]
<type 'list'>
三.生成器的一些方法
1.next()方法查看元素
li = ( i for i in range(5))
print li ##打印出的是生成器地址
print type(li) ##查看li的类型为'generator'
print next(li) ##第一次遍历元素 0
print li.next() ##第二次遍历元素 1
print li.next() ##第三次遍历元素 2
print li.next() ##第四次遍历元素 3
print li.next() ##第五次遍历元素 4
print li.next() ##第六次因为元素已经遍历完了所以会抛出异常StopIteration
执行结果
<generator object <genexpr> at 0x7f8272d5eb40> ##生成器地址
<type 'generator'> ##类型为生成器
0
1
2
3
4
Traceback (most recent call last):
File "/home/kiosk/PycharmProjects/3.16/3.17.py", line 511, in <module>
print li.next()
StopIteration
2.close()方法关闭生成器
g = ( i for i in range(5))
print next(g) ##第一次输出结果为0
print g.next() ##第二次为1
print g.next() ##第三次为2
g.close() ##第三次之后关闭,终止生成器
print g.next() ##所以这次以及以后会报错StopIteration
执行结果
0
1
2
Traceback (most recent call last):
File '/home/kiosk/PycharmProjects/3.16/3.17.py', line 509, in <module>
print g.next()
StopIteration
对于生成器g
g = ( i for i in range(5))
while 1:
try:
print g.next()
except StopIteration:
print '生成器元素没了'
break
执行结果
0
1
2
3
4
生成器元素没了
3.yield:
# 函数中如果有yield, 那么调用这个函数的返回值为生成器。
# 当生成器g调用next方法, 执行函数, 直到遇到yield就停止;
# 再执行next,从上一次停止的地方继续执行;
# 函数中遇return直接退出, 不继续执行后面代码;当函数中出现yield则默认该函数为生成器,
throw 给生成器发送一个异常
try的工作原理是,当开始一个try语句后,python就在当前程序上下文中作标记,这样当出现异常时,就可以返回这里,try子句先执行,接下来会发生什么依赖于执行时是否会出现异常; 当try语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完成后,控制流就通过整个try语句(除非再处理异常时又出现新的异常); 如果try后的语句发生了异常,却没有匹配到except子句,异常将被递交到上层的try,或者程序最上层,这样将结束程序,并打印出缺省的出错信息。
执行完主函数的一条任务后,python会在第一时间返回到try中,
对于下边的程序:
(1) python控制流到def gen():发现定义了个函数,跳到主函数if name == ‘main‘:
(2)流程到主函数这里,进行下一步g = gen()发现是个生成器,进行下一步
(3)需要打印生成器的第一个元素,需要返回定义的函数,生成器
(4)返回生成器后遇到while 1:,为真执行循环:读取try命令,遇到yield ‘a’,做标记,并输出a,返回主函数的第二条打印命令
(5)输出同样是需要返回生成器,返回定义的生成器,在上一次标记位置yield ‘a’,跳到try的yield ‘a’的下条命令:yield ‘b’,并输出“b“
(6)打印完成后,进行下一步:此时g.throw(TypeError)给生成器抛了一个TypeError异常,返回生成器上次标记位:yield ‘b’:进行异常处理:except比对匹配异常,并处理,打印出’测试throw方法’,异常处理完成后,这时python控制权交给try,并标记yield ‘a’这里;接着控制流读取主函数的下一条命令,就是第三条打印命令发现需要返回生成器:返回生成器从标记处yield ‘a’读取下一条命令yield ‘b’会打印出b
(7)打印完成后读取主函数第四条打印命令,同样需要返回生成器;此时去try那里,重新标记,到yield ‘a’生成a,打印出a
(8)完成后执行第5条打印命令,继续返回生成器,由于上次控制流驻留在yield ‘a’处,所以第5条命令会打印出b
(9)完成后,主函数遇到g.throw(ValueError)异常:返回生产器,except逐一匹配异常,并做处理,打印出Value Error,之后控制流重新到try,并在yield ‘a’处标记驻留,
(10)返回主函数执行第六条打印任务,同样需要返回生成器,上次驻留在yield ‘a’处,所以第5条打印任务会打印出b
(11)第7条打印任务,返回生成器时,上次留在yield ‘b’处,所以这次会从头生成a,同样停在a处
def gen():
while 1:
try:
yield 'a'
yield 'b'
except TypeError:
print '测试throw方法'
except ValueError:
print 'Value Error'
if __name__ == '__main__':
g = gen()
print g.next()
print next(g)
g.throw(TypeError)
print g.next()
print g.next()
print g.next()
g.throw(ValueError)
print g.next()
print g.next()
执行结果
a
b
测试throw方法
b
a
b
Value Error
b
a
*.send()方法,用于给生成器发送某一信息,
def res():
while 1:
receive = yield ' '
if receive == 'a':
print "收到a"
elif receive == 'b':
print '收到b'
else:
print '不清楚大哥你发的什么?'
g=res()
next(g)
info =raw_input('info:')
g.send(info)
运行一下:
info:qww
不清楚大哥你发的什么?
实验:
def chat_robot():
res = ''
while True:
receive = yield res
if '你好' in receive or 'hi' in receive:
res = '你好,我是机器人小冰!'
elif "年龄" in receive:
res = '小冰1岁了!'
elif 'name' in receive or '名字' in receive:
res = '你的名字呢?'
else:
res = '小冰不知道你在说什么?正在学习中......'
Chat = chat_robot()
Chat.next()
while True:
send_info = raw_input('>>A:').strip()
if send_info == 'bye':
print '机器人不和你玩了!'
break
response = Chat.send(send_info)
print '小冰>>:%s' %(response)
Chat.close
实验效果:
四.生成器_无缓冲区的生产消费者模型
import time
import random
def consumer(name):
print '[%s]准备买粉条...' % name
while True:
kind = yield
print '客户[%s]购买了[%s]口味的粉条...' %(name ,kind)
def producer(pname):
c1 = consumer('WANG')
c2 = consumer('Leo')
c1.next()
next(c2)
print '厨师[%s]准备制作粉条。。。' %(pname)
for kind in ['三鲜','麻辣','特辣']:
time.sleep(random.random()*5)
print '[%s]制作了[%s]口味的粉条...' %(pname,kind)
c1.send(kind)
c2.send(kind)
c1.close()
c2.close()
producer('TOM')
运行结果:
[WANG]准备买粉条...
[Leo]准备买粉条...
厨师[TOM]准备制作粉条。。。
[TOM]制作了[三鲜]口味的粉条...
客户[WANG]购买了[三鲜]口味的粉条...
客户[Leo]购买了[三鲜]口味的粉条...
[TOM]制作了[麻辣]口味的粉条...
客户[WANG]购买了[麻辣]口味的粉条...
客户[Leo]购买了[麻辣]口味的粉条...
[TOM]制作了[特辣]口味的粉条...
客户[WANG]购买了[特辣]口味的粉条...
客户[Leo]购买了[特辣]口味的粉条...
五.生成器_有缓冲区的生产消费者模型
“
import time
import random
cache =[]
def consumer(name):
print ‘[%s]准备买粉条…’ % name
while True:
kind = yield
cache.remove(kind)
print ‘客户[%s]购买了[%s]口味的粉条…’ %(name ,kind)
def producer(pname):
print '厨师[%s]准备制作粉条。。。' %(pname)
for kind in ['三鲜','麻辣','特辣']:
time.sleep(random.random()*5)
print '[%s]制作了[%s]口味的粉条...' %(pname,kind)
cache.append(kind)
producer(“TOM”)
c1 = consumer(‘WANG’)
c1.next()
c1.send(‘三鲜’)
print ‘本店现有粉条口味: ’ ,
for i in cache:
print i,
“
运行结果
厨师[TOM]准备制作粉条。。。
[TOM]制作了[三鲜]口味的粉条...
[TOM]制作了[麻辣]口味的粉条...
[TOM]制作了[特辣]口味的粉条...
[WANG]准备买粉条...
客户[WANG]购买了[三鲜]口味的粉条...
本店现有粉条口味: 麻辣 特辣
生成器的优势总结:
- 生成器提供了一种更为便利的产生迭代器的方式, 一般用户不需要自己实现iter和next方法,它默认返回一个可迭代对象;
- 代码更为简洁,优雅;
- 节省存储空间