一,生成器
2.1初始生成器
我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。
Python中提供的生成器:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器Generator:
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
2.2 生成器函数
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
import time def genrator_fun1(): a = 1 print('现在定义了a变量') yield a b = 2 print('现在又定义了b变量') yield b g1 = genrator_fun1() print('g1 : ',g1) #打印g1可以发现g1就是一个生成器 print('-'*20) #我是华丽的分割线 print(next(g1)) time.sleep(1) #sleep一秒看清执行过程 print(next(g1))
生成器有什么好处呢?就是不会一下子在内存中生成太多数据
假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。
def produce(): """生产衣服""" for i in range(2000000): yield "生产了第%s件衣服"%i product_g = produce() print(product_g.__next__()) #要一件衣服 print(product_g.__next__()) #再要一件衣服 print(product_g.__next__()) #再要一件衣服 num = 0 for i in product_g: #要一批衣服,比如5件 print(i) num +=1 if num == 5: break
# 生成器:就是自己python用代码写的迭代器,生成器的本质就是迭代器。 l1 = [1,2,3] iter1 = iter(l1) # 用以下两种方式构建一个生成器: # 1,通过生成器函数。 # 2,生成器表达式。 # 生成器函数: # 函数 def func1(x): x += 1 return x func1(5) #函数的执行命令,并且接受函数的返回值。 print(func1(5)) # 生成器函数 def func1(x): x += 1 print(1111) print(1111) print(1111) print(1111) print(1111) print(1111) yield x x +=2 print(2222) yield 'alex' x +=3 g_obj = func1(5) # 生成器函数对象 # print(g_obj) # <generator object func1 at 0x0000025E5D618780> print(g_obj.__next__()) print(g_obj.__next__()) #一个next 对应一个 yield #yield 将值返回给 生成器对象.__next__() #yield return #return 结束函数,给函数的执行者返回值 #yield 不会结束函数,一个next对应一个yield,给 生成器对象.__next__() 返回值。 # 生成器函数 vs 迭代器 # 区别1:自定制的区别 # l1 = [1,2,3,4,5] # l1.__iter__() # def func1(x): # x += 1 # yield x # x += 3 # yield x # x += 5 # yield x # g1 = func1(5) # print(g1.__next__()) # print(g1.__next__()) # print(g1.__next__()) # 区别1:内存级别的区别。 # 迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。 # 生成器直接创建,不需要转化,从本质就节省内存。 # def func1(): # for i in range(1000000): # yield i # g1 = func1() # for i in range(50): # print(g1.__next__())
2.3 send
def generator(): print(123) content = yield 1 print('=======',content) print(456) yield2 g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello') #send的效果和next一样 print('***',ret) #send 获取下一个值的效果和next基本一致 #只是在获取下一个值的时候,给上一yield的位置传递一个数据 #使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值
# send 与 next def func1(): # print(1) count = yield 6 print(count) # print(2) count1 = yield 7 print(count1) # print(3) yield 8 # g = func1() # next(g) # # g.send('alex') # g.send('alex') # g.send('太白') # g.send('太白') # send 与next一样,也是对生成器取值(执行一个yield)的方法。 # send 可以给上一个yield 传值。 # 第一次取值永远都是next。 # 最后一个yield 永远也得不到send传的值。 # def cloth1(n): # for i in range(n+1): # print('衣服%s号' % i) # cloth1(100000) def cloth2(n): for i in range(1,n+1): yield '衣服%s号' % i g = cloth2(10000) for i in range(50): print(g.__next__()) for i in range(50): print(g.__next__())
三,列表推导式和生成器表达式
l = [i for i in range(10)] print(l) l1 = ['选项%s'%i for i in range(10)] print(l1)
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
sum(x ** 2 for x in range(4))
# l1 = [] # for num in range(1,101): # l1.append(num) # print(l1) # 列表推导式:一行代码几乎搞定你需要的任何的列表。 # 循环模式 [变量(加工后的变量) for 变量 in iterable] # l = [i for i in range(1,101)] # print(l) # l2 = ['python%s期' % i for i in range(1,16)] # print(l2) # print([i*i for i in range(1,11)]) # 筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件] # l3 = [i for i in range(1,31) if i % 2 == 0] # print(l3) # print([i for i in range(1,31) if i % 3 == 0]) # print([i**2 for i in range(1,31) if i % 3 == 0]) names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([j for i in names for j in i if j.count('e') == 2]) # 列表推导式 # 优点:一行解决,方便。 # 缺点:容易着迷,不易排错,不能超过三次循环。 # 列表推导式不能解决所有列表的问题,所以不要太刻意用。 # 生成器表达式:将列表推导式的 [] 换成() 即可。 # g = (i for i in range(100000000000)) # print(g) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) # # mcase = {'a': 10, 'b': 34} # mcase_frequency = {mcase[k]: k for k in mcase} # print(mcase_frequency) # squared = {x**2 for x in [1, -1, 2]} # print(squared)
各种推导式玩法
推导式套路
之前我们已经学习了最简单的列表推导式和生成器表达式。但是除此之外,其实还有字典推导式、集合推导式等等。
下面是一个以列表推导式为例的推导式详细格式,同样适用于其他推导式。
variable = [out_exp_res for out_exp in input_list if out_exp == 2] out_exp_res: 列表生成元素表达式,可以是有返回值的函数。 for out_exp in input_list: 迭代input_list将out_exp传入out_exp_res表达式中。 if out_exp == 2: 根据条件过滤哪些值可以。
列表推导式
例一:30以内所有能被3整除的数
multiples = [i for i in range(30) if i % 3 is 0] print(multiples) # Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
例二:30以内所有能被3整除的数的平方
def squared(x): return x*x multiples = [squared(i) for i in range(30) if i % 3 is 0] print(multiples)
例三:找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍历顺序,这是实现的关键
字典推导式
例一:将一个字典的key和value对调
mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)
例二:合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
print(mcase_frequency)
集合推导式
例:计算列表中每个值的平方,自带去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])
练习题:
例1: 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
例2: 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表
例3: 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
生成器:自己用python代码写的,本质上迭代器。 生成器函数。 yield yield 与 return 区别: return 结束函数,返回给函数的执行者返回值。 yield 不会结束函数,会将值返回给生成器对象。 next 与 send 区别。 共同点:都可以从生成器(迭代器)里取值。 不同点: send给上一个yield发送一个值。 第一个一定要用next,因为他上一个没有yield ,会报错。最后一个yield 永远得不到send值。 生成器表达式。 列表推导式。 两种模式: 1,循环模式。[变量(加工后的变量) for 变量 in iterable] 2,筛选模式。[变量(加工后的变量) for 变量 in iterable if 条件] 生成器表达式。 列表推导式 与生成器表达式的不同。 1,形式上不同 [] () 2,内存级别不同。生成器表达式非常节省内存。
# # Day12作业默写 # 1,整理今天的博客,写课上代码,整理流程图。 # 2,用列表推导式做下列小题 # (1) 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 # (2) 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的 元祖 列表 # l1 = [(),(),....] # print([(2*x,2*x+1) for x in range(0,3)]) # print([(x,y) for x in range(0,6) if x % 2 == 0 for y in range(0,6) if y % 2 == 1]) # print([(x,y) for x in range(0,5,2)for y in range(1,6,2)]) # (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]] # print([x[-1] for x in M]) # print([[x-2,x-1,x] for x in [3,6,9]]) # (4) 求出50以内能被3整除的数的平方,并放入到一个列表中。 # (5) 构建一个列表: # ['python1期', 'python2期', 'python3期', 'python4期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期'] # (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) 有一个列表l1 = ['alex', 'WuSir', '老男孩', '太白'] # 将其构造成这种列表['alex0', 'WuSir1', '老男孩2', '太白3'] # (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]] # print([[i['timestamp'],i['values']] for i in x['Values']]) # 3,求结果: # v = [i % 2 for i in range(10)] # print(v) # # # 4,求结果: # v = (i % 2 for i in range(10)) # print(v) # # 5,求结果: # # def func1(): # for i in range(5): # print(i) # print(i) # # #
# l1 = [] # for i in range(1,101): # l1.append(i) # # print(l1) # l2 = ['python%s期'%i for i in range(1,16)] # print(l2) # l3 = [i*i for i in range(1,11)] # print(l3) #例一:30以内所有能被3整除的数 # l4 = [i for i in range(1,31) if i % 3 ==0] # print(l4) #例二:30以内所有能被3整除的数的平方 # l5 = [i**2 for i in range(1,31) if i % 3 == 0 ] # print(l5) # #例三:找到嵌套列表中名字含有两个‘e’的所有名字 # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], # ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] # l6 = [j for i in names for j in i if j.count('e') ==2 ] # print(l6) # # # # Day12作业默写 # 1,整理今天的博客,写课上代码,整理流程图。 # 2,用列表推导式做下列小题 # (1) 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 # (2) 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的 元祖 列表 # l1 = ['abcd','ab','bded','a','c','eee'] # ret = [i.upper() for i in l1 if len(i) >= 3] # print(ret) # # x = [i for i in range(0,6) if i % 2 ==0] # y = [i for i in range(0,6) if i % 2 ==1] # print(x) # print(y) # l2 = [(xx,yy) for xx in x for yy in y] # print(l2) # # l3 = [(yy,xx) for xx in x for yy in y] # print(l3) # l1 = [(),(),....] # print([(2*x,2*x+1) for x in range(0,3)]) # print([(x,y) for x in range(0,6) if x % 2 == 0 for y in range(0,6) if y % 2 == 1]) # print([(x,y) for x in range(0,5,2)for y in range(1,6,2)]) # (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]] #print([[x-2,x-1,x] for x in [3,6,9]]) # M = [[1,2,3],[4,5,6],[7,8,9]] # print([x[-1] for x in M]) # print([[x-2,x-1,x] for x in [3,6,9]]) # (4) 求出50以内能被3整除的数的平方,并放入到一个列表中。 # ret = [x**2 for x in range(0,51) if x % 3 ==0] # print(ret) # (5) 构建一个列表: # ['python1期', 'python2期', 'python3期', 'python4期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期'] # (6) 构建一个列表:[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)] # print([(x,x+1) for x in range(0,6)]) # (7) 构建一个列表:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] #print([x*2 for x in range(0,10)]) # (8) 有一个列表l1 = ['alex', 'WuSir', '老男孩', '太白'] # 将其构造成这种列表['alex0', 'WuSir1', '老男孩2', '太白3'] l1 = ['alex', 'WuSir', '老男孩', '太白'] #print([i+str(l1.index(i)) for i in l1]) # (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]] #print([[xx['timestamp'],xx['values']] for xx in x['Values']]) # print([[i['timestamp'],i['values']] for i in x['Values']]) # 3,求结果: v = [i % 2 for i in range(10)] print(v) # # # 4,求结果: v = (i % 2 for i in range(10)) print(v) # # 5,求结果: # def func1(): for i in range(5): print(i) print(i) # # #
posted on
浙公网安备 33010602011771号