初识生成器与生成器表达式 Day12
2018-09-19 02:51:52来源:博客园 阅读 ()
一、生成器
1,生成器基本概念
生成器的实质是迭代器
迭代器:Iterator 内部同时包含了__iter__()和__next__()函数 可迭代对象:Iterable 内部包含__iter__()函数 迭代器的特点:(同时也是生成器特点) 1,节省内存 2,惰性机制 3,不能反复只能向下执行
在Python中有三种方法来获取生成器:
1. 通过生成器函数
2. 通过各种推导式来实现生成器
3.通过数据的转换也可以获取生成器
示例:先看一个简单的函数:
def func(): print("111") return 222 ret = func() print(ret) 结果: 111 222
再将函数中的return换成yield变成生成器函数:
def func(): print("111") yield 222 ret = func() print(ret) 结果: <generator object func at 0x10647a8e0>
可以看出结果是不一样的。由于函数中存在了yield,那么这个函数就是一个生成器函数。我们再执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器。
因为生成器的本质是迭代器,所以我们可以直接执行__next__()以下生成器:
def func(): print("111") yield 222 gener = func() # 这个时候函数不会执行,只是获取到生成器 ret = gener.__next__() # 函数执行,yield和return的作用一样,返回数据 print(ret) 结果: 111 222
所以,yield和return的效果是一样的,都是返回数据,但还是有很大区别的:
yield是分段来执行一个函数;return是直接停止执行函数
2,生成器的send()方法:
send()和__next__()一样都可以让生成器执行到下一个yield
def eat(): print("meat") a = yield "milk" print('baozi', a) b = yield 'zhou' print('guobaorou', b) yield 'tea' gen = eat() ret = gen.__next__() print(ret) ret = gen.__next__() print(ret) ret = gen.send("MIANBAO") # 给上一个yield传值 print(ret) ret = gen.send("DANGAO") # 给上一个yield传值 print(ret) 结果: meat milk baozi None zhou guobaorou MIANBAO tea Traceback (most recent call last): ret = gen.send("DANGAO") # 给上一个yield传值 StopIteration
send()和__next__():
1. send和next都是让生成器向下走一次
2. send可以给上一个yield的位置传递值,不能给最后一个yield发送值。也不能在第一次执行生成器代码的时候不能使用send()
3,使用for循环
def func(): yield "a" yield "b" yield "c" gen = func() for el in gen: print(el) # 结果: # a # b # c
使用for循环的话会获取内部所有的元素
二、列表推导式,生成器表达式以及其他推导式
1,列表推导式
常用写法:[结果 for循环 if筛选]
筛选模式:[结果 for 变量 in 可迭代对象 if 条件]
练习题:
# (1)创建列表:[1,3,5,7,9,...99] l2 = [i for i in range(1,100) if i % 2 == 1] # [结果 for循环 if筛选] print(l2) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99] # 列表推导式 # (1) 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 lst = ['hello', 'world', 'hh', 'old', 'boy', 'H'] l1 = [i.upper() for i in lst if len(i) >= 3] print(1, l1) # (2) 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表 l2 = [(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1] # l2 = list(zip([x for x in range(6) if x % 2 == 0], [y for y in range(6) if y % 2 == 1])) print(2, l2) # (3) 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]] M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] l3 = [el[2] for el in M] print(3, l3) # (4) 求出50以内能被3整除的数的平方,并放入到一个列表中。 l4 = [i*i for i in range(1, 50) if i % 3 == 0] print(4, l4) l4_1 = [i for i in range(1, 50) if i % 3 == 0 and i*i < 50] print(l4_1) # (6) 构建一个列表:[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)] # l6 = [(x, y) for x in range(6) for y in range(1, 7)] l6 = [(x, x+1) for x in range(6)] print(6, l6) # (7) 构建一个列表:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] l7 = [i for i in range(0, 19, 2)] print(7, l7) # (8)有一个列表l1 = ['alex', 'WuSir', '老男孩', '太白']将其构造成这种列表['alex0', 'WuSir1', '老男孩2', '太白3'] ll = ['alex', 'WuSir', '老男孩', '太白'] l8 = [v+str(i) for i, v in enumerate(ll)] print(8, l8) # l8 = [] # for i,v in enumerate(ll): # v = v+str(i) # print(v,i) # (9)有以下数据类型: x = { 'name': 'alex', 'Values': [ {'timestamp':1517991992.94, 'values':100,}, {'timestamp': 1517992000.94, 'values': 200,}, {'timestamp': 1517992014.94, 'values': 300,}, {'timestamp': 1517992744.94, 'values': 350}, {'timestamp': 1517992800.94, 'values': 280} ], } # 将上面的数据通过列表推导式转换成下面的类型: # [[1517991992.94, 100], [1517992000.94, 200], [1517992014.94, 300], [1517992744.94, 350], [1517992800.94, 280]] l9 = [[el['timestamp'], el['values']] for el in x['Values']] print(9, l9) # 结果: 1 ['HELLO', 'WORLD', 'OLD', 'BOY'] 2 [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)] 3 [3, 6, 9] 4 [9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304] [3, 6] 6 [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)] 7 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 8 ['alex0', 'WuSir1', '老男孩2', '太白3'] 9 [[1517991992.94, 100], [1517992000.94, 200], [1517992014.94, 300], [1517992744.94, 350], [1517992800.94, 280]]
# (5) 寻找名字中带有两个e的人的名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] # l5 = [] # for i in range(len(names)): # for j in names[i]: # if j.count('e') >= 2: # l5.append(j) l5 = [j for i in range(len(names)) for j in names[i] if j.count('e') >= 2] print(l5) # 主要注意str.count()的运用,查找字符串数量
2,生成器表达式:
语法与列表推导式基本上是一样的。只是把 [] 替换成 {}
gen = (i for i in range(10)) # 生成表达式 print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) print(gen.__next__()) # print(gen.__next__()) # 超出数量会报错 # 结果: # 0 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9
生成器表达式与列表推导式的区别:
1,列表推导式比较耗内存,一次性加载;而生成器表达式几乎不占用内存,使用的时候才分配和使用内存。
2,得到的值不一样:列表推导式得到的是一个列表,生成器表达式获得的是一个生成器。
生成器的惰性求值:生成器只有在访问的时候才取值。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Python学习日记(十) 生成器和迭代器 2019-08-13
- python学习-39 生成器总结 2019-07-24
- python学习-38迭代器和生成器 2019-07-24
- Python-11-生成器 2019-07-24
- Redis初识01 (简介、安装、使用) 2019-07-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash